第四章 列表
列表和元组可以包含多个值,这样编写程序来处理大量数据就变得容易。而且列表本身又可以包含其他列表,所以可以用它们将数据安排成层次结构。
列表定义:"列表"是一个值,它包含多个字构成的序列。术语"列表值"指的是列表本身(它作为一个值,可以保存在变量中,或传递给函数,像其他数据类型一样)
组成部分:左方括号开始,右方括号结束,即[],列表中的值也称为“表项”,表项用逗号分隔,如[1,2,3,4,5]
用下标取得列表中的单个值
列表中的表项是依次从左到右,下标从0开始,取出列表中的表项:
>>>spam = [[1,2],1,'cat','dog'] >>>spam[0] # 下标只能是整数,不能是浮点数,但是也可以为负数,表示从右向左开始依次类推。 [1,2] >>>spam[1] 1 >>>spam[2] 'cat' >>>spam[3] 'dog' >>>spam[-1] 'dog' >>>spam[-2] 'cat'
上面的例子,如果想要取出列表中的列表的中的值,可以通过多重下标来访问:
>>>spam = [[1,2],1,'cat','dog'] >>>spam[0][0] 1 >>>spam[0][1] 2
用切片取得子列表
就像下标可以从列表中取得单个值一样,"切片"可以从列表中取得多个值,生成一个新的列表。
- 在一个切片中,第一个数是切片开始处的下标(包括它),第二个数是切片结束的下标(但不包括它)。
>>>spam[1:2] [1] >>>spam[0:2] [[1,2],1]
- 快捷方法,也可以省略切片中":"两边的一个或两个下标。
>>>spam[1:] [1,'cat','dog'] >>>spam[:2] [[1,2],1] >>>spam[:] [[1,2],1,'cat','dog']
用len()取得列表的长度
len()函数将返回传递给它的列表中值的个数:
>>>spam = [[1,2],1,'cat','dog'] >>>len(spam) 4
常和循环一起使用:
循环是针对一个列表或类似列表中的每个值,重复地执行代码块。
spam = ['elephant',1,'cat','dog'] for i in range(len(spam)): print('index'+ str(i) + 'item:' + spam[i]) #输出 index 0 item:elephant index 1 item:1 index 2 item:cat index 3 item:dog # 在前面的循环中使用range(len(spam))很方便,这是因为,循环中的代码可以访问下标(通过变量i),以及下标处的值(通过spam(i)。最妙的是range(len(spam))将迭代spam的所有下标,无论它包含多少表项。
列表的连接和复制(和字符串的连接类似)
操作符+:可以连接两个列表,得到一个新的列表
操作符*:可以用于1个列表和1个整数,实现列表的复制
列表的增、删、改、查
增加
- 使用append()添加表项到列表末尾
>>>spam = [[1,2],1,'cat','dog'] >>>spam.append('elephant') >>>spam [[1,2],1,'cat','dog','elephant']
- 使用insert()方法根据下标插入表项,第一个参数是新值的下标,第二个参数是要插入的新值
>>>spam = [[1,2],1,'cat','dog'] >>>spam.insert(1,'elephant') >>>spam [[1,2],'elephant',1,'cat','dog']
注意:append()和insert()返回值都是None.
删除
- del语句根据下标删除列表中的值
>>>spam = [[1,2],1,'cat','dog'] >>>del spam[1] >>>spam [[1,2],'cat','dog']
- 使用remove()方法从列表中删除值
>>>spam = [[1,2],1,'cat','dog']
>>>spam.remove('cat') # 如果列表中存在重复的值,就删除它第一次出现值
>>>spam
[[1,2],1,'dog']
修改
通过列表的下标,来改变下标处的值
>>>spam = [[1,2],1,'cat','dog'] >>>spam[1] = 'philippines' >>>spam [[1,2],'philippines','cat','dog']
查看
- 通过下标进行查看
>>>spam = [[1,2],1,'cat','dog'] >>>spam[1] 1
- 知道列表中表项的情况下,通过index()查询下标
>>>spam = [[1,2,1,'cat','dog'] #如果列表中存在重复的值,就返回它第一次出现的下标 >>>spam.index(1) 0
用sort()方法将列表中的值排序
>>>spam = [2,5,7,9,1,0] >>> spam.sort() >>>spam [0,1,2,5,7,9] >>>spam = ['a','q','A','E'] >>>spam.sort() >>>spam #输出 ['A', 'E', 'a', 'q']
也可以指定reverse关键字参数为True,让sort()按逆序排序。
spam = ['a','q','A','E'] spam.sort(reverse=True) print(spam) #输出 ['q', 'a', 'E', 'A'] #注意: sort()返回值也是None. sort()方法对字符串排序时,使用"ASCII"字符排序,小写在前大写在后
in和not in操作符
利用in 和not in操作符,可以确定一个值是否在列表中。
>>>'dick' in ['dick','jacky','maria'] True >>>spam = ['dick','jacky','maria'] >>> 'sophie' in spam False >>> 'sophie' not in spam True
多重赋值技巧
多重赋值技巧是一种快捷方式,让你在一行代码中,用列表中的值为多个变量赋值。所以不必像这样:
>>>user_database = ['dick,123123,0] >>>username = user_database[0] >>>password = user_database[1] >>>history = user_database[2] 而是输入以下代码: >>>user_database = ['dick,123123,0] >>>username,password,history = user_database #变量的数目和列表的长度必须严格相等,否则报错。
增强的赋值操作
>>>spam = 42 >>>spam +=1 >>>spam 43
作为一种快捷方式,可以使用增强的赋值操作符+=来完成同样的事:
>>>spam = 'hello' >>>spam += 'world' >>>spam "hello world" >>>bacon = ['zophie'] >>>bacon+=3 >>>bacon ['zophie','zophie','zophie']
和字符串的异同
字符串可以理解为是单个字符的列表
相同点:
对列表的许多操作,也可以作用于字符串:
按下标取值
切片
用于for循环
len()
in 和not in操作符
可变和不可变数据类型
列表是可变的数据类型,它的值可以添加、删除或改变,
字符串是不可变的,它不能被更改:改变字符串的正确方式只能使用切片和连接,构造一个新的字符串
尽管列表值是可变的,但下面代码中的第二行并没有修改列表spam:
>>>spam = [1,2,3] >>>spam = [4,5,6] >>>spam [4,5,6]
这里的spam中的列表值并没有改变,而是整个新的列表值([4,5,6]),覆写了老的列表值。如果确实希望修改原来的列表,那么:
>>>spam = [1,2,3] >>>del spam[2] >>>del spam[1] >>>del spam[0] >>>spam.append(4) >>>spam.append(5) >>>spam.append(6) >>>spam [4,5,6]
#改变一个可变数据类型的值(就像上面例子中del语句和append()方法所做的事)当场改变了该值,因为该变量的值没有被一个新的列表值取代。
这个例子中,spam最后的列表值与它开始的列表值是一样的。只是这个列表被改变了,而不是被覆写。
接下来,我们来看看元组数据类型,他是列表数据类型的不可变形式
元组数据类型
元组和列表只有2点区别:1.元组使用(),2.元组不可变
如果元组中只有一个值,你可以在括号内该值后面跟上一个逗号,表明它是一个元组。
>>>type(('hello',)) <class 'tuple'> >>>type(('hello')) <class 'str'>
如果你需要一个永远不改变的序列,就用元组。
元组与列表之间的转换
使用list()和tuple()函数来转换类型
>>>tuple([1,2,3]) >>>(1,2,3) >>>list('hello') ['h','e','l','l','o']
如果需要元组值得一个可变版本,将元组转换成列表:
>>>list((1,2,3)) [1,2,3]
引用
变量保存字符串和整数值:
>>>spam =42 >>>cheese = spam >>> spam = 100 >>> spam 100 >>> cheese 42 #你将42赋给spam变量,然后拷贝spam中的值,将它赋给变量chees。后面将spam值改变为100后,这不会影响cheese中的值。这是因为spam和cheese是不同的变量,保存了不同的值。
但是,
列表不是这样的。当你将列表赋给一个变量时,实际上是将列表的"引用"赋给了该变量。引用是一个值,指向某些数据。列表引用指向同一个列表的值
>>>spam = [1,2,3,4,5,6] >>>cheese = spam >>>cheese[1] = 'hello' >>>spam [1,'hello',3,4,5,6] >>>cheese [1,'hello',3,4,5,6] #当创建列表spam时,你将对它的引用赋给了变量。但是下一行cheese只是将spam中的列表"引用"拷贝到cheese,而不是列表值本身。这意味着存储在spam和cheese中的值,现在指向了同一个列表。底下只有一个列表,因为列表本身实际从未复制。所以当你修改cheese变量的第一个元素时,也修改了spam指向的同一个列表。
总结:列表变量实际上没有包含列表,而是包含了对列表的“引用”(这些引用包含一些ID数字,Python在内部使用这些ID)
spam = [1,2,3,4,5,6] #保存了对列表的引用,而非实际列表 spam = cheese #复制了引用,而非列表
所以,对于字符串和整数值或元组,变量就包含了字符串(str)或整数(int)或元组(tuple),Python变量就使用值本身。而在变量必须保存可变数据类型(列表或字典)的值时,Python就使用引用。
copy模块的copy()个deepcopy()函数
import copy
copy.copy(): #用来复制列表或字典这样的可变值,而不只是复制引用 copy.deepcopy(): #用来复制的列表中包含了列表,就使用这个函数,该函数将同时复制它们内部的列表
习题:
1.什么是[]?
答:列表是一个值,它由多个字符构成的序列
2.如何将'hello'赋给列表的第三个值,而列表保存在名为spam的变量中?(假定变量包含[2,4,6,8,10])
答:直接赋值即可,spam[2] = 'hello' 就将'hello'赋值给列表的第三个值
对接下来的3个问题,假定spam包含列表['a','b','c','d']
3.spam[int('3'*2)/11]求值为多少?
答:'a'
4.spam[-1]求值为多少?
答:'d'
5.spam[:2]求值为多少?
答:['a','b']
对接下来的3个问题。假定bacon包含列表[3.14,'cat',11'cat',True]
6.bacon.index('cat')求值为多少?
答:1
7.bacon.append(99)让bacon中的列表值变成什么样?
答:[3.14,'cat',11'cat',True,99]
8.bacon.remove('cat')让bacon中的列表值变成什么样?
答:[3.14,'cat',11,True]
9.列表链接和复制的操作符是什么?
答:列表连接:+,列表复制*
10.append()和insert()列表方法之间的区别是什么?
答:append()是将值插入到列表的最后,而insert()是将值插入任意的位置。
11.从列表中删除值有哪两种方法?
答:del和remove
12.请说出列表值和字符串的几点相似之处。
答:字符串是单个文本字符的列表,1.都可以使用下标进行取值,切片 2.都可以使用+/*操作符进行连接和复制 3.用于for循环/len(),in 和not in操作符
13.列表和元组之间的区别是什么?
答:列表中的值是可变的,元组是不可改变的
14.如果元组中只有一个整数值42,如何输入该元组?
答:(42,)
15.如何从列表值得到元组形式?如何从元组值得到列表形式?
答:使用list()方法和tuple()方法
16.“包含”列表的变量,实际上并未真正的直接包含列表。他们包含的是什么?
答:包含了对列表的引用,这些引用包含了同一块内存地址,并不是真正的列表
17.copy.copy()和copy.deepcopy()之间的区别是什么?
答:copy.copy()可以用来复制列表或字典这样的数据类型,而不是复制引用;而copy.deepcopy()是同时复制他们内部的列表