Python 3.8从零开始学
上QQ阅读APP看书,第一时间看更新

3.2.1 更新列表

序列所拥有的特性,列表都有。在3.1节中所介绍的有关序列的操作,如索引、分片、相加、乘法等操作都适用于列表。本节将介绍一些序列中没有而列表中有的方法,这些方法的作用都是更新列表,如元素赋值、增加元素、删除元素、分片赋值和列表方法等。下面将逐一进行介绍。

1.元素赋值

前面的章节已经大量使用了赋值语句,赋值语句是最简单的改变列表的方式,如a=2就属于一种改变列表的方式。

创建一个列表,列表名为group,group中存放“序列号”上第一组所有5名同学的序号,通过编号标记某个特定位置的元素,对该位置的元素重新赋值,如group[1]=9,就可以实现元素赋值。

拿“序列号”上所有同学的序号来举例,第一组5位同学的序号分别是0、1、2、3、4。由于某种需要,需要序号为1的同学与序号为9的同学交换一下位置及所在的组,对于1和9号同学,各自交换一下座位即可,而导游则将序号为9的同学纳入第一组,序号为1的同学纳入第二组。

这个生活场景读者应该不难理解。而对于计算机来说,比这个生活场景更简单。创建列表group,赋值[0,1,2,3,4]后,计算机就在内存中为group变量开辟了一块内存空间,内存空间中存放数据的形式如图3-1所示。

当执行group[1]=9后,计算机会找到group变量,并找到索引下标为1的内存地址,将内存为1的地址空间的值擦除,再更改上9这个值,就完成了赋值操作,如图3-2所示。

图3-1 内存空间

图3-2 内存空间

在图3-2中可以看到,下标为1对应的数值已经更改为9了,此处为便于读者观察,在下标为1处用了一个波浪线作为特别提示。从此时开始,group列表中的值就变更为0、9、2、3、4了,后续再对group操作,就是在这个列表值的基础上进行操作了。

用代码实现上述操作如下:

>>> group=[0,1,2,3,4]
>>> group[1]=9      #索引下标为1的元素重新赋值为9
>>> group
[0, 9, 2, 3, 4]
>>> group[3]=30     #同理,可以将索引下标为3的元素重新赋值为30
>>> group
[0, 9, 2, 30, 4]

这里不要忘记索引下标的编号是从0开始的。

由输出结果可以看到,可以根据索引下标编号对列表中某个元素重新赋值。

既然可以重新赋值,是否可以对列表中的元素赋不同类型的值呢?对上面得到的group列表,在交互模式下做如下尝试:

>>> group[2]='xiaomeng'     #对编号为2的元素赋值,赋一个字符串
>>> group
[0, 9, 'xiaomeng', 30, 4]
>>> type(group)
<class 'list'>
>>> type(group[1])          #别忘了查看类型函数的使用
<class 'int'>
>>> type(group[2])
<class 'str'>

由输出结果可以看到,可以对一个列表中的元素赋以不同类型的值。在上面的示例中,列表group中既有int类型的值,也有str类型的值。

假如对列表赋值时,使用的索引下标编号超过了列表中的最大索引下标编号,是否可以赋值成功?得到结果会是怎样的?继续对group列表操作,group列表中当前有5个元素,最大索引下标是4,即group[4],这里尝试对group[5]赋值,在交互模式下输入:

>>> group
[0, 9, 'xiaomeng', 30, 4]
>>> group[5]='try'
Traceback (most recent call last):
File "<pyshell#134>", line 1, in <module>
group[5]='try'
IndexError: list assignment index out of range

在上面的示例中,group列表的最大索引下标编号是4,当给索引下标编号为5的元素赋值时出错,错误提示的信息是:列表索引超出范围。

提示


不能为一个不存在元素的位置赋值,若强行赋值,程序会报错。

2.增加元素

由上面元素赋值的示例可以看到,不能为一个不存在的元素位置赋值,列表一旦创建,就不能再向这个列表中增加元素了。

不能向列表中增加元素这种情况可能会让我们比较难堪,毕竟在实际项目应用中,一个列表到底要创建为多大,经常是不能预先知道的。

那么,这种问题该怎么处理呢?列表增加元素的操作在实际应用中会有比较多的应用场景,也是一个高频次的操作,Python中是否提供了对应的方法帮助我们做这件事情呢?

答案是肯定的。接着上面的示例,下面尝试将字符串try添加到group列表中。在交互模式下  输入:

>>> group
[0, 9, 'xiaomeng', 30, 4]
>>> group.append('try')
>>> group
[0, 9, 'xiaomeng', 30, 4, 'try']

由示例输出结果看到,在Python中提供了一个append()方法,该方法可以帮助我们解决前面遇到的困惑。

append()方法是一个用于在列表末尾添加新对象的方法。append()方法的语法格式如下:

list.append(obj)

此语法中,list代表列表,obj代表需要添加到list列表末尾的对象。

提示


append()方法的使用方式是list.append(obj),list要为已经创建的列表,obj不能为空。

对于append()方法的使用,需要补充说明:append()方法操作列表时,返回的列表不是一个新列表,而是直接在原来的列表上做修改,然后将修改过的列表直接返回。如果是创建新列表,就会多出一倍的存储空间。以group列表为例,未使用append()方法之前,group列表中的内容是[0, 9, 'xiaomeng', 30, 4],这是已经占用了一块存储空间的值。使用append()方法后,若创建了新列表,就会在内存中再开辟一块新的存储空间,新开辟的存储空间中存放的内容是[0, 9, 'xiaomeng', 30, 4, 'try'],和原列表比起来,就相当于增加了一倍的存储空间。而直接修改列表的情形会是这样的:内容是[0, 9, 'xiaomeng', 30, 4]的存储空间继续占有,使用append()方法后,会在现有的存储空间中增加一小块内存,用来存放新增加的try字符串,相对于原列表,仅仅增加了try字符串所占据的存储,而不是增加一倍的存储空间。

使用append()方法,可以向列表中增加各种类型的值。

继续操作group列表,append()使用的示例如下:

>>> group
[0, 9, 'xiaomeng', 30, 4, 'try']
>>> group.append('test')         #向列表添加字符串
>>> group
[0, 9, 'xiaomeng', 30, 4, 'try', 'test']
>>> group.append(3)             #向列表添加数字
>>> group
[0, 9, 'xiaomeng', 30, 4, 'try', 'test',3]

3.删除元素

由上面的示例输出接口可以得知:可以向数字序列中添加字符串,也可以向字符串序列中添加数字。

前面学习了向列表中增加元素,可以使用append()方法来实现。列表中既然可以增加元素,那是否可以删除元素呢?

继续操作group列表,示例如下:

>>> group
[0, 9, 'xiaomeng', 30, 4, 'try', 'test']
>>> len(group)        #使用序列中获取长度的函数
7
>>> del group[6]     #删除最后一个元素,注意索引下标与序列长度的关系
>>> print('删除最后一个元素后的结果:',group)
删除最后一个元素后的结果: [0, 9, 'xiaomeng', 30, 4, 'try']
>>> len(group)
6
>>> group
[0, 9, 'xiaomeng', 30, 4, 'try']
>>> del group[2]      #删除索引下标为2的元素
>>> print('删除索引下标为2的元素后的结果:',group)
删除索引下标为2的元素后的结果: [0, 9, 30, 4, 'try']
>>> len(group)
5

由输出结果可以看到,使用del可以删除列表中的元素。

上面的示例中使用del删除了group列表中的第7个元素,删除元素后,原来有7个元素的列表会变成有6个元素的列表。

使用del除了可以删除列表中的字符串,也可以删除列表中的数字。

继续操作group列表,在交互模式下输入:

>>> group
[0, 9, 30, 4, 'try']
>>> len(group)
5
>>> del group[3]
>>> print('删除索引下标为3的元素后的结果:',group)
删除索引下标为3的元素后的结果: [0, 9, 30, 'try']
>>> len(group)
4

由输出结果可以看到,已经从group列表中删除了对应的数字。

除了删除列表中的元素,del还能用于删除其他元素,具体将在后续章节做详细介绍。

4.分片赋值

分片赋值是列表一个强大的特性。已经在3.1节讲解过分片的定义与实现。

在继续往下之前需要补充一点:如前面所说,通过a=list()的方式可以初始化一个空的列表。但若写成如下形式:

list(str)或a=list(str)

则list()方法会将字符串str转换为对应的列表,str中的每个字符将被转换为一个列表元素,包括空格字符。list()方法可以直接将字符串转换为列表。该方法的一个功能就是根据字符串创建列表,有时这么操作会很方便。list()方法不仅适用于字符串,所有类型的序列它都适用。

>>> list('北京将举办2020年的冬奥会')
['北', '京', '将', '举', '办', '2', '0', '2', '0', '年', '的', '冬', '奥', '会']
>>> greeting=list('welcome to beijing')
>>> greeting
['w', 'e', 'l', 'c', 'o', 'm', 'e', ' ', 't', 'o', ' ', 'b', 'e', 'i', 'j', 'i', 'n', 'g']
>>> greeting[11:18]
['b', 'e', 'i', 'j', 'i', 'n', 'g']
>>> greeting[11:18]=list('china')
>>> greeting
['w', 'e', 'l', 'c', 'o', 'm', 'e', ' ', 't', 'o', ' ', 'c', 'h', 'i', 'n', 'a']

由输出结果可以看到,可以直接使用list()将字符串变换为列表,也可以通过分片赋值直接对列表进行变更。

示例中我们首先将字符串“北京将举办2020年的冬奥会”使用list()方法转变为列表,接着将字符串“welcome to beijing”也使用list()方法转变为列表,并将结果赋值给greeting列表。最后通过分片操作变更greeting列表中索引下标编号为11到18之间的元素,即将beijing替换为china。

除了上面展示的功能,分片赋值还有什么强大的功能呢?先看下面的示例:

>>> greeting=list('hi')
>>> greeting
['h', 'i']
>>> greeting[1:]=list('ello')
>>> greeting
['h', 'e', 'l', 'l', 'o']

分析如下:首先给greeting列表赋值['h', 'i'],后面通过列表的分片赋值操作将编号1之后的元素变更,即将编号1位置的元素替换为e,但是编号2之后没有元素,怎么能操作成功呢?并且一直操作到编号为4的位置呢?

这就是列表的分片赋值的另一个强大的功能:可以使用与原列表不等长的列表将分片进行替换。

除了分片替换,列表的分片赋值还有哪些新功能呢?接着看下面的示例:

>>> field=list('ae')
>>> field
['a', 'e']
>>> field[1: 1]=list('bcd')
>>> field
['a', 'b', 'c', 'd', 'e']
>>> goodnews=list('北京将举办冬奥会')
>>> goodnews
['北', '京', '将', '举', '办', '冬', '奥', '会']
>>> goodnews[5: 5]=list('2022年的')
>>> goodnews
['北', '京', '将', '举', '办', '2', '0', '2', '2', '年', '的', '冬', '奥', '会']

由输出结果可以看到,使用列表的分片赋值功能,可以在不替换任何原有元素的情况下在任意位置插入新元素。读者可自行尝试在上面示例的其他位置进行操作。

当然,上面的示例程序的实质是“替换”了一个空分片,实际发生的操作是在列表中插入了一个列表。

该示例的使用是否让你想起了前面使用过的append()方法,不过分片赋值比append()方法的功能强大很多,append()方法只能在列表尾部增加元素,不能指定元素的插入位置,并且一次只能插入一个元素;而分片赋值可以在任意位置增加元素,并且支持一次插入多个元素。

看到这里,是否同时想起了前面删除元素的操作,分片赋值是否支持类似删除的功能呢?

分片赋值中也提供了类似删除的功能。示例如下:

>>> field=list('abcde')
>>> field
['a', 'b', 'c', 'd', 'e']
>>> field[1: 4]=[]
>>> field
['a', 'e']
>>> field=list('abcde')
>>> del field[1: 4]
>>> field
['a', 'e']
>>> goodnews=list('北京将举办2022年的冬奥会')
>>> goodnews
['北', '京', '将', '举', '办', '2', '0', '2', '2', '年', '的', '冬', '奥', '会']
>>> goodnews[5: 11]=[]
>>> goodnews
['北', '京', '将', '举', '办', '冬', '奥', '会']

从上面的输出结果可以看到,通过分片赋值的方式,将想要删除的元素赋值为空列表,可以达到删除对应元素的效果。并且列表中的分片删除和分片赋值一样,可以对列表中任意位置的元素进行删除。