第5章 列表、元组和字符串-上
5.1 列表:一个”打了激素”的数组
当你需要存储一堆东西时,你可能需要把它放在某种”集合”中,因为将来可能会用得上。在别的编程语言中大多数都是用数组。由于Python的变量没有数据类型,也就是说,Python没有数组的。但是呢,Python加入了更为强大的列表。
Python的列表有多强大?如果把数组比作一个集装箱的话,那么Python的列表就是一个工厂的仓库了。列表真的非常好用,基本上所有的Python程序都要用到列表,包括之前的打飞机游戏,里边的小飞机可以全部丢到一个列表中统一管理。
5.1.1 创建列表
创建列表和创建普通变量一样,用中括号括起一堆数据就可以啦,数据之间用逗号隔开,这样就创建好一个列表啦
>>> number = [1,2,3,4,5]
>>> number
[1, 2, 3, 4, 5]
为什么是打了激素的数组?因为可以创建一个鱼龙混杂的列表,什么数据类型都可以放进去。
>>> mix = [1,'小甲鱼',3.14,[1,2,3]]
>>> mix
[1, '小甲鱼', 3.14, [1, 2, 3]]
列表可以放整型、字符串、浮点型数据,还可以包含另外一个列表
如果不知道放什么数据,可以先创建一个空列表,用到的时候再拿来用
>>> empty = []
5.1.12 向列表添加元素
列表相当灵活,所以它的内容不可能总是固定的,向列表添加元素,可以使用append()方法:
>>> number = [1,2,3,4,5]
>>> number.append(6)
>>> number
[1, 2, 3, 4, 5, 6]
参数6已经被添加到列表的number的末尾了。有疑问,为什么这个方法调用跟平时的BIF内置函数调用不一样呢?嗯,因为append()不是一个BIF,而是属于列表对象的一个方法。中间的这个”.”可以理解为是什么东西下面的方法这类的,可以说成,number下面的append的方法,append()这个方法是属于一个叫做number的列表对象的。对象之后再详细讲。
除了这种还有没有另外一种,我抱着作死的心态开始了一次测试:
>>> number.append(7,8)
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
number.append(7,8)
TypeError: append() takes exactly one argument (2 given)
按照上面的操作,然后就报错啦,我的想法是把数字7和8添加进去,但是我们不能使用append()同时添加多个元素:
这时候就可以使用extend()方法向列表末尾添加多个元素:
>>> number.extend(7,8)
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
number.extend(7,8)
TypeError: extend() takes exactly one argument (2 given)
怎么又报错啦,其实小甲鱼是故意的。extend()方法事实上使用一个列表来扩展另一个列表,所以它参数应该是一个列表:
>>> number.extend([7,8])
>>> number
[1, 2, 3, 4, 5, 6, 7, 8]
刚才实现的是往列表的末尾添加数据,那如果我想”插队”?什么插队?不好吧,很容易得罪人家,这个”插队”是列表允许的。
想要往列表的任意位置插入元素,就可以使用insert()方法。
insert()方法有两个参数:
第一个参数是代表的在列表中的位置,第二个参数是在这个位置处插入一个元素。
让数字0出现在列表的最前边,开始第一次尝试,实现了结果了吗?:
>>> number.insert(1,0)
>>> number
[1, 0, 2, 3, 4, 5, 6, 7, 8]
为什么0插到了第二个位置,而不是插到第一个位置?其实凡是顺序索引,Python均从0开始,同时也是大多数编程语言约定俗成的规范。
为什么要用0来表示第一个数吗?
因为计算机本身就是二进制的,在二进制的世界里面只有两个数:0和1,当然,0就是二进制里的第一个数了,所以0也就习惯用于表示第一个数。
正确的做法应该是:
>>> number = [1, 2, 3, 4, 5, 6, 7, 8]
>>> number.insert(0,0)
>>> number
[0, 1, 2, 3, 4, 5, 6, 7, 8]
5.1.3 从列表中获取元素
跟数组一样,可以通过元素的索引值(index)从列表获取单个元素,注意,列表索引值是从0开始的:
利用索引值,每次可以从列表获取一个元素:
>>> name = ['鸡蛋','鸭蛋','鹅蛋','李狗蛋']
>>> name[0]
'鸡蛋'
>>> name[1]
'鸭蛋'
实现互换位置,使”李狗蛋”和”鸭蛋”的位置互换:
>>> name[1],name[3] = name[3],name[1]
>>> name
['鸡蛋', '李狗蛋', '鹅蛋', '鸭蛋']
5.1.4 从列表删除元素
有三种方法:
remove(),del和pop()
先演示一下用remove()删除元素:
>>> name.remove('李狗蛋')
>>> name
['鸡蛋', '鹅蛋', '鸭蛋']
使用remove()删除元素,你并不需要知道这个元素所在的位置,只需要知道有这个元素存在就可以啦。
如果要删除的东西根本不在列表中,程序就会报错:
>>> name.remove('陈鸭蛋')
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
name.remove('陈鸭蛋')
ValueError: list.remove(x): x not in list
remove()方法并不能指定某个位置的元素,这时要用del来实现:
>>> del name[1]
>>> name
['鸡蛋', '鸭蛋']
PS.del是一个语句,而不是一个列表的方法,所以不必在它的后面加上小括号()。另外,如果你是想删除整个列表,还可以这样直接使用del加列表名删除
>>> del name
>>> name
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
name
NameError: name 'name' is not defined
删除整个列表之后,因为已经删除了,所以是不存在的,会报错
pop()方法”弹出”元素
>>> name = ['鸡蛋','鹅蛋','鸭蛋','李狗蛋']
>>> name.pop()
'李狗蛋'
>>> name
['鸡蛋', '鹅蛋', '鸭蛋']
pop()方法默认是弹出列表最后一个元素。但这个pop()方法其实还可以灵活运用,当你为他家加上一个索引值作为参数的时候,它会弹出这个索引值对应的元素:
>>> name = ['鸡蛋','鹅蛋','鸭蛋','李狗蛋']
>>> name.pop(2)
'鸭蛋'
>>> name
['鸡蛋', '鹅蛋', '李狗蛋']
5.1.5 列表分片
利用列表的分片(slice),可以实现一次性获取多个元素:
>>> name = ['鸡蛋','鹅蛋','鸭蛋','李狗蛋']
>>> name[0:2]
['鸡蛋', '鹅蛋']
使用一个冒号隔开两个索引值。左闭右开[start:end)
PS.利用列表分片,得到一个原来列表的拷贝,原来的列表并没有发生改变
列表分片可以简写,现在来尝试一下你所想的是否可行:
- 没有开始位置,默认开始位置为0
- 有开始位置,没有结束位置(得到从指定索引值到列表末尾的所有元素,把结束位置省去)
- 开始和结束位置都没写,只有冒号(没有放入然和索引值,而只有一个冒号,将得到真个列表的拷贝)
>>> name[:2]
['鸡蛋', '鹅蛋']
>>> name[1:]
['鹅蛋', '鸭蛋', '李狗蛋']
>>> name[:]
['鸡蛋', '鹅蛋', '鸭蛋', '李狗蛋']
PS.列表分片就是建立原列表的一个拷贝(副本),适用情况:你想对列表做出某些修改,但同时还向保持的那个列表。
5.1.6 列表分片的进阶玩法
分片操作实际上还可以接受第三个参数,其代表的是步长(step),默认为1
>>> list1 = [1,2,3,4,5,6,7,8,9]
>>> list1[0:9:2]
[1, 3, 5, 7, 9]
上面的这个还有写成list1[::2]
如果步长是负数,例如-1结果是?
>>> list1[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1]
step设置为-1,就相当于复制一个反转列表。
就像好像这个列表有一个假循环,但是好像是存在的
5.1.7 一些常用操作符
厉害了,我的列表,居然可以比较大小
>>> list1 = [123]
>>> list2 = [234]
>>> list1 > list2
False
>>> list3 = ['abc']
>>> list4 = ['bcd']
>>> list3 < list4
True
列表元素中不止一个元素:
>>> list1 = [123,456]
>>> list2 = [234,123]
>>> list1 > list2
False
当列表包含多个元素时,默认从第一个元素比较,只要有一个赢了,计算整个列表赢了。字符串比较也是同样的原理(字符串比较的是第一个字符对应的ASCII码值的大小)
列表加号(+)也叫做连接操作符,实现拼接,可以将多个列表对象合并在一起:
>>> list1 = [123,456]
>>> list2 = [234,123]
>>> list3 = list1 +list2
>>> list3
[123, 456, 234, 123]
extend()方法来扩展列表,因为这样可以显得你好专业,哈哈哈
列表的extend()方法是把新参数添加到原有列表中,id不变,相当于原地修改。
>>> list1 = [123,456]
>>> list2 = [234,123]
>>> list1.extend(list2)
>>> list1
[123, 456, 234, 123]
PS.加号(连接操作符)并不能实现添加新元素的操作:
>>> list1 = [123,456]
>>> list2 = list1 +789
Traceback (most recent call last):
File "<pyshell#37>", line 1, in <module>
list2 = list1 +789
TypeError: can only concatenate list (not "int") to list
乘号(*)也叫做重复操作符
>>> list1 = [123]
>>> list1 * 3
[123, 123, 123]
复合赋值运算符:
>>> list1 = [123]
>>> list1 *= 5
>>> list1
[123, 123, 123, 123, 123]
成员关系操作符in和not in:
>>> list1 = ['小猪','小猫','小狗','小甲鱼']
>>> '小甲鱼' in list1
True
>>> '小护士' not in list1
True
列表可以包含另外一个列表,对于列表中的列表元素,能不能使用成员关系操作符:
>>> list1 = ['小猪','小猫',['小甲鱼','小护士'],'小狗']
>>> '小甲鱼' in list1
False
>>> '小护士' not in list1
True
in和not in只能判断一个层次的成员关系(要判断列表里边的列表的元素,应该先进入一层列表)
>>> list1 = ['小猪','小猫',['小甲鱼','小护士'],'小狗']
>>> '小甲鱼' in list1[2]
True
>>> '小护士' not in list1[2]
False
访问二维列表,找到小甲鱼:
>>> list1 = ['小猪','小猫',['小甲鱼','小护士'],'小狗']
>>> list1[2][0]
'小甲鱼'
5.1.8 列表的小伙伴
列表有很多个小伙伴,不信,请看:
>>> dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
下面是关于几个常用的方法:
count():计算它的参数在列表中出现的次数:
>>> list1 = [1,1,2,3,5,8,13,21]
>>> list1.count(1)
2
index():会返回它的参数在列表中的位置:
>>> list1.index(1)
0
如果那个参数不存在的话,会报错
>>> list.index(6)
Traceback (most recent call last):
File "<pyshell#65>", line 1, in <module>
list.index(6)
TypeError: descriptor 'index' requires a 'list' object but received a 'int'
这里是返回第一个目标(1)在list1的位置,index()方法还有两个参数,用于限定查找的范围。
这样可以找到第二个目标在list1的位置:
>>> start = list1.index(1) + 1
>>> stop = len(list1)
>>> list1.index(1,start,stop)
1
raverse():反转列表,将个列表原地反转
>>> list1 = [1,2,3,4,5,6,7,8]
>>> list1.reverse()
>>> list1
[8, 7, 6, 5, 4, 3, 2, 1]
sort():用指定方式对列表的成员进行排序,默认不需要参数,从小到大排队:
>>> list1 = [8,9,3,5,6,10,1,0]
>>> list1.sort()
>>> list1
[0, 1, 3, 5, 6, 8, 9, 10]
sort(fun,key,reverse)
sort(reverse = True)把reverse的值设置为True,就可以实现从大到小排队
>>> list1 = [8,9,3,5,6,10,1,0]
>>> list1.sort(reverse = True)
>>> list1
[10, 9, 8, 6, 5, 3, 1, 0]
5.1.9 关于分片”拷贝”概念的补充
使用分片创建列表的拷贝:
>>> list1 = [1,3,2,9,7,8]
>>> list2 = list1[:]
>>> list2
[1, 3, 2, 9, 7, 8]
>>> list3 = list1
>>> list3
[1, 3, 2, 9, 7, 8]
上面看起来是一样的,对吧,使用sort()做一下修改
>>> list1.sort()
>>> list1
[1, 2, 3, 7, 8, 9]
>>> list2
[1, 3, 2, 9, 7, 8]
>>> list3
[1, 2, 3, 7, 8, 9]
使用分片方式得到的list2没有发生改变,而list3发生改变了
为一个列表指定一另一个名字的做法.只是同一个列表增加一个新的标签而已,真正的拷贝是要使用分片的方法
参考资料是:零基础入门学习Python小甲鱼的书和视频教程