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

3.2.3 列表方法

方法是与对象有紧密联系的函数,对象可能是列表、数字,也可能是字符串或其他类型的对象。方法的调用语法格式如下:

对象.方法(参数)

比如前面用到的append()方法就是这种形式的,由列表方法的语法和前面append()方法的示例可知,方法的调用方式是将对象放到方法名之前,两者之间用一个点号隔开,方法后面的括号中可以根据需要带上参数。除了语法上有一些不同,方法调用和函数调用很相似。

列表中有append()、extend()、index()、sort()等常用的方法,下面逐一进行介绍。

1.append()

append()方法的语法格式如下:

list.append(obj)

此语法中,list代表列表,obj代表待添加的对象。

append()方法在前面已经介绍过,该方法的功能是在列表的末尾添加新对象。

在实际项目应用中,列表中的append()方法是使用频率最高的一个方法,涉及列表操作的,都或多或少需要用到append()方法进行元素的添加。

2.extend()

extend()方法的语法格式如下:

list.extend(seq)

此语法中,list代表被扩展列表,seq代表需要追加到list中的元素列表。

extend()方法用于在列表末尾一次性追加另一个列表中的多个值(用新列表扩展原来的列表),也就是列表的扩展。

在extend()方法的使用过程中,list列表会被更改,但不会生成新的列表。

使用该方法的示例如下:

>>> a=['hello','world']
>>> b=['python','is','funny']
>>> a.extend(b)
>>> a
['hello', 'world', 'python', 'is', 'funny']

由操作结果可知,extend()方法很像序列连接的操作。

extend()方法和序列相加有什么不同之处?先看看下面的示例:

>>> a=['hello','world']
>>> b=['python','is','funny']
>>> a+b
['hello', 'world', 'python', 'is', 'funny']
>>> a
['hello', 'world']
>>> a.extend(b)
>>> a
['hello', 'world', 'python', 'is', 'funny']

由输出结果可以看到,使用序列相加和使用extend()得到的结果是相同的,但使用序列相加时,并不改变任何变量的值,而使用extend()方法时,会更改变量的值。

由此我们得出,extend()方法和序列相加的主要区别是:extend()方法修改了被扩展的列表,如这里的a,执行a.extend(b)后,a的值变更了;原始的连接操作会返回一个全新的列表,如上面的示例中,a与b的连接操作返回的是一个包含a和b副本的新列表,而不会修改原始的变量。

上述示例也可以使用前面学习的分片赋值来实现,在交互模式下输入:

>>> a=['hello','world']
>>> b=['python','is','funny']
>>> a[len(a):]=b
>>> a
['hello', 'world', 'python', 'is', 'funny']

可以看到,最终得到的结果和使用extend()方法一样,不过看起来没有extend()方法易懂,这里只是作为一个演示示例,在实际项目开发过程中,不建议使用该方式。

在实际项目应用中,extend()方法也是一个使用频率较高的方法,特别是在涉及多个列表的合并时,使用extend()方法非常便捷。

3.index()

index()方法的语法格式如下:

list.index(obj)

此语法中,list代表列表,obj代表待查找的对象。

index()方法用于从列表中搜索某个值,返回列表中找到的第一个与给定参数匹配的元素的索引下标位置。

使用该方法的示例如下:

>>> field=['hello', 'world', 'python', 'is', 'funny']
>>> print('hello的索引位置为:',field.index('hello'))
hello的索引位置为: 0
>>> print('python的索引位置为:',field.index('python'))
python的索引位置为: 2
>>> print('abc的索引位置为:',field.index('abc'))
Traceback (most recent call last):
File "<pyshell#221>", line 1, in <module>
print('abc的索引位置为:',field.index('abc'))
ValueError: 'abc' is not in list

由输出结果可以看到,当使用index()方法搜索字符串hello时,index()方法返回字符串hello在列表中的索引位置0;使用index()方法搜索字符串python时,index()方法返回字符串python在序列中的索引位置2,索引得到的位置跟元素在序列中的索引下标编号一样。如果搜索的是列表中不存在的字符串,就会出错,所以对于不在列表中的元素,用index()方法操作会报错。

在实际项目应用中,index()方法的使用不是很多,在功能上,使用in可以达到和index()相同的功能,除非要返回搜索对象的具体索引位置时,才考虑使用index()方法,其他情形使用in会更高效和便捷。

4.insert()

insert()方法的语法格式如下:

list.insert(index,obj)

此语法中,list代表列表,index代表对象obj需要插入的索引位置,obj代表要插入列表中的对象。

insert()方法用于将对象插入列表。

使用该方法的示例如下:

>>> num=[1,2,3]
>>> print('插入之前的num:',num)
插入之前的num: [1, 2, 3]
>>> num.insert(2,'插入位置在2之后,3之前')
>>> print('插入之后的num:',num)
插入之后的num: [1, 2, '插入位置在2之后,3之前', 3]

由上面的操作过程及输出结果可以看到,insert()方法操作列表是非常方便的。

与extend()方法一样,insert()方法的操作也可以使用分片赋值实现。

>>> num=[1,2,3]
>>> print('插入之前的num:',num)
插入之前的num: [1, 2, 3]
>>> num[2:2]=['插入位置在2之后,3之前']
>>> print('插入之后的num:',num)
插入之后的num: [1, 2, '插入位置在2之后,3之前', 3]

输出结果和insert()操作的结果一样,但看起来没有使用insert()容易理解。

在实际项目应用中,insert()方法较多地用于在列表指定位置插入指定元素,多用于单个元素的插入,当涉及大量元素插入时,使用分片赋值要更好一些。

5.sort()

sort()方法的语法格式如下:

list.sort(func)

此语法中,list代表列表,func为可选参数。如果指定该参数,就会使用该参数的方法进行   排序。

sort()方法用于对原列表进行排序,如果指定参数,就使用参数指定的比较方法进行排序。

使用该方法的示例如下:

>>> num=[5,8,1,3,6]
>>> num.sort()
>>> print('num调用sort方法后:',num)
num调用sort方法后: [1, 3, 5, 6, 8]

由上面输出的结果可知,sort()方法改变了原来的列表,即sort()方法是直接在原来列表上做修改的,而不是返回一个已排序的新的列表。

我们前面学习过几个改变列表却不返回值的方法(如append()方法),不能将操作结果赋给一个变量,这样的行为方式在有一些情况下是非常合常理并且很有用的。如果用户只是需要一个排好序的列表的副本,同时又需要保留列表原本结构不变时,使用不修改列表结构的方法就很有必要了。操作示例如下:

>>> num=[5,8,1,3,6]
>>> n=num.sort()
>>> print('变量n的结果是:',n)
变量n的结果是: None
>>> print('列表num排序后的结果是:',num)
列表num排序后的结果是: [1, 3, 5, 6, 8]

由输出结果可以看到,输出结果和我们预期的不一样。这是因为sort()方法修改了列表num,但sort()方法是没有返回值的,或返回的就是一个None,所以我们最后看到的是已排序的num和sort()方法返回的None。

要想实现结构不改变的num变量,又要使num变量值排序,正确的实现方式是先把num的值赋给变量n,然后使用sort()方法对n进行排序,在交互模式下输入:

>>> num=[5,8,1,3,6]
>>> n=num                                #将列表num赋值给n
>>> n.sort()
>>> print('变量n的结果是:',n)
变量n的结果是: [1, 3, 5, 6, 8]
>>> print('num的结果是:',num)             #num也被排序了
num的结果是: [1, 3, 5, 6, 8]
>>> num=[5,8,1,3,6]
>>> n=num[:]                           #将列表num切片后赋值给n
>>> n.sort()
>>> print('变量n的结果是:',n)
变量n的结果是: [1, 3, 5, 6, 8]
>>> print('num的结果是:',num)              #num保持原样
num的结果是: [5, 8, 1, 3, 6]

由上面的执行结果可以看到,通过直接将变量num的值赋给变量n,对n使用sort()方法排序后,原来的num变量也被排序了,这是为什么呢?

这是因为在内存的分配中,num变量创建时,计算机为num变量分配了一块内存,用于存放num指向的变量值,当执行n=num时,计算机并没有再开辟一块新的内存用于存放变量n所指向的变量值,而是将n指向了与num相同的一块内存地址,也就是这时变量num和n都是指向同一块内存地址。所以当使用sort()方法对n做排序后,内存中的值发生变化,所以最后打印出来的num变量值也是排序后的变量值。

同时也可以看到,将num分片后的值赋给变量n后,对n进行排序的结果不影响num的变量值。这是因为对num分片后赋值给变量n时,变量n开辟的是一块新的内存空间,也就是变量n指向的内存与变量num不是同一块了,所有对变量n的操作不会影响变量num。

在项目实战时,要注意该类问题的处理,若不想更改原列表的数据结构,又想对变量值做排序,可以对原列表分片后赋给一个新变量,对新变量进行排序即可。

在Python中,sort()方法有一个有同样功能的函数——sorted函数。该函数可以直接获取列表的副本进行排序,sorted函数的使用方式如下:

>>> num=[5,8,1,3,6]
>>> n=sorted(num)
>>> print('变量n的操作结果是:',n)
变量n的操作结果是: [1, 3, 5, 6, 8]
>>> print('num的结果是:',num)      #num保持原样
num的结果是: [5, 8, 1, 3, 6]

执行结果和前面操作的一样。sorted函数可以用于任何序列,返回结果都是一个列表。例如下面的操作:

>>> sorted('python')
['h', 'n', 'o', 'p', 't', 'y']
>>> sorted('321')
['1', '2', '3']

在实际项目应用中,sort()方法应用频率不是很高,在需要涉及一些稍微简单的排序时会使用sort()方法,很多时候可能需要开发者自己实现有针对性的排序方法。

6.copy()

copy()方法的语法格式如下:

list.copy()

此语法中,list代表列表,不需要传入参数。

copy()方法用于复制列表,类似于 a[:]。使用该方法的示例如下:

>>> field=['study','python','is','happy']
>>> copyfield=field.copy()
>>> print('复制操作结果:',copyfield)
复制操作结果: ['study', 'python', 'is', 'happy']

操作结果和该方法的意思一样,是原原本本的复制操作。

对于前面遇到的sort()方法中的困惑,可以通过copy()方法来解决,具体实现如下:

>>> num=[5,8,1,3,6]
>>> num
[5, 8, 1, 3, 6]
>>> n=num.copy()
>>> n
[5, 8, 1, 3, 6]
>>> n.sort()
>>> n
[1, 3, 5, 6, 8]
>>> num
[5, 8, 1, 3, 6]

由输出结果可以看到,调用copy()方法后,对n进行排序,并不影响num变量的值。

在实际项目应用中,copy()方法的使用频率不是很高,但copy()方法是一个比较有用的方法,在列表的结构复制上很好用,效率也比较高。

由上面的示例看到,调用pop方法移除元素时,在交互模式下会告知我们移除了哪个元素,如上面示例中的funny、is。移除funny时未传参数,默认移除最后一个;is的移除则是根据传入的编号3进行的。

使用pop方法可以实现一种常见的数据结构——栈。

栈的原理就像堆放盘子一样,一次操作一个盘子,要将若干盘子堆成一堆,只能在一个盘子的上面放另一个盘子;要拿盘子时,只能从顶部一个一个往下拿,最后放入的盘子是最先被拿的。栈也是这样,最后放入栈的最先被移除,称为LIFO(Last In First Out),即后进先出。

栈中的放入和移除操作有统一的称谓——入栈(push)和出栈(pop)。Python没有入栈方法,但可以使用append方法代替。pop方法和append方法的操作结果恰好相反,如果入栈(或追加)刚刚出栈的值,最后得到的结果就不会变,例如以下操作:

>>> num=[1, 2, 3]
>>> num.append(num.pop())         #追加默认出栈的值
>>> print('num追加默认出栈值的操作结果:',num)
num追加默认出栈值的操作结果: [1, 2, 3]

由上面的操作结果看到,通过追加默认出栈的值得到的列表和原来是一样的。

7.remove()

remove()方法的语法格式如下:

list.remove(obj)

此语法中,list代表列表,obj为列表中要移除的对象。

remove()方法用于移除列表中某个值的第一个匹配项。使用该方法的示例如下:

>>> good=['女排','精神','中国','精神','学习','精神']
>>> >>> print('移除前列表good:',good)
移除前列表good: ['女排', '精神', '中国', '精神', '学习', '精神']
>>> good.remove('精神')
>>> print('移除后列表good:',good)
移除后列表good: ['女排', '中国', '精神', '学习', '精神']
>>> good.remove('happy')  #删除列表中不存在的元素
Traceback (most recent call last):
File "<pyshell#238>", line 1, in <module>
good.remove('happy')
ValueError: list.remove(x): x not in list

由输出结果可以看到,remove()只移除列表中找到的第一个匹配值,找到的第二个之后的匹配值不会被移除。

通过查看上面定义的列表,通过计数,可以知道列表中有3个“精神”,调用移除方法remove()后,删除了第一个,后面两个仍然在列表中。

同时,不能移除列表中不存在的值,系统会告知移除的对象不在列表中。

此处需要补充一点:remove()方法没有返回值,是一个直接对元素所在位置变更的方法,它修改了列表却没有返回值。

在实际项目应用中,remove()方法的使用频率不高。

8.pop()

pop()方法的语法格式如下:

list.pop(obj=list[-1])

此语法中,list代表列表,obj为可选择的参数,代表要移除列表元素的对象。

pop()方法用于移除列表中的一个元素,并且返回该元素的值。

在使用pop()方法时,若没有指定需要移除的元素,则默认移除列表中的最后一个元素。pop()方法的使用示例如下:

>>> field=['hello', 'world', 'python', 'is', 'funny']
>>> field.pop()  #不传参数,默认移除最后一个元素
'funny'
>>> print('移除元素后的field:',field)
移除元素后的field: ['hello', 'world', 'python', 'is']
>>> field.pop(3)  #移除编号为3的元素
'is'
>>> print('移除元素后的field:',field)
移除元素后的field: ['hello', 'world', 'python']
>>> field.pop(0)
'hello'
>>> print('移除元素后的field:',field)
移除元素后的field: ['world', 'python']

由输出结果可以看到,调用pop()方法移除元素时,在交互模式下会告知我们此次操作移除了哪个元素,如上面示例中的funny、is。在对field变量使用pop()方法的过程中,有一处没有指定移除哪个元素,结果默认移除了funny这个元素,即列表的最后一个元素;is的移除则是根据传入的索引下标编号3进行的。

提示


在Python中,pop()方法是唯一一个既能修改列表又能返回元素值(除了None)的列表方法。

使用pop()方法可以实现一种常见的数据结构——栈。

栈的原理就像堆放盘子一样,一次操作一个盘子,要将若干盘子堆成一堆,只能在一个盘子的上面放另一个盘子;要拿盘子时,只能从顶部一个一个地往下拿,最后放入的盘子是最先被拿的。栈也是这样,最后放入栈的元素最先被移除,称为LIFO(Last In First Out),即后进先出。

栈中的放入和移除操作有统一的称谓——入栈(push)和出栈(pop)。Python没有入栈方法,但可以使用append()方法代替。pop()方法和append()方法的操作结果恰好相反,如果入栈(或追加)刚刚出栈的值,最后得到的结果就不会变,例如:

>>> num=[1,2,3]
>>> num.append(num.pop())         #追加默认出栈的值
>>> print('num追加默认出栈值的操作结果:',num)
num追加默认出栈值的操作结果: [1, 2, 3]

由操作结果可以看到,通过追加默认出栈的值得到的列表和原来的是一样的。

在实际项目应用中,pop()方法的使用频率并不高,但不能以此否认pop()方法的使用价值,pop()是一个非常有使用价值的方法,在一些问题的处理上它有独特的功能特性,读者在使用时可以多加留意。

9.reverse()

reverse()方法的语法格式如下:

list.reverse()

此语法中,list代表列表,该方法不需要传入参数。

reverse()方法用于反向列表中的元素。使用该方法的示例如下:

>>> num=[1,2,3]
>>> print('列表反转前num:',num)
列表反转前num: [1, 2, 3]
>>> num.reverse()
>>> print('列表反转后:',num)
列表反转后: [3, 2, 1]

由输出结果可以看到,该方法改变了列表但不返回值(和前面的remove()方法一样)。

提示


如果需要对一个序列进行反向迭代,那么可以使用reversed函数。这个函数并不返回列表,而是返回一个迭代器(Iterator)对象(该对象在后面会详细介绍),可以通过list函数把返回的对象转换为列表,例如:

>>> num=[1, 2, 3]
>>> print('使用reversed函数翻转结果:', list(reversed(num)))
使用reversed函数翻转结果: [3, 2, 1]

输出结果对原序列反向迭代了。

在实际项目应用中,reverse()方法一般会配合sort()方法一起使用,目的是更方便于排序,为排序节省时间或内存开销,对于不同业务场景会有不同的节省方式。

10.clear()

clear()方法的语法格式如下:

list.clear()

此语法中,list代表列表,不需要传入参数。

clear()方法用于清空列表,类似于 del a[:]。使用该方法的示例如下:

>>> field=['study','python','is','happy']
>>> field.clear()
>>> print('field调用clear方法后的结果:',field)
field调用clear方法后的结果: []

由操作结果看到,clear()方法会清空整个列表,调用该方法进行清空操作很简单,但也要小心,因为一不小心就可能把整个列表都清空了。

在实际项目应用中,clear()方法一般应用在涉及大量列表操作,且类别元素比较多的场景中,在列表元素比较多时,一般会涉及分批次的操作,每批次操作时,为减少对内存的占用,一般会使用clear()方法先清空列表,高效且快速。

11.count()

count()方法的语法格式如下:

list.count(obj)

此语法中,list代表列表,obj代表列表中统计的对象。

count()方法用于统计某个元素在列表中出现的次数。使用该方法的示例如下:

>>> field=list('hello,world')
>>> field
['h', 'e', 'l', 'l', 'o', ',', 'w', 'o', 'r', 'l', 'd']
>>> print('列表field中,字母o的个数:',field.count('o'))      #统计列表中的字符个数
列表field中,字母o的个数: 2
>>> print('列表field中,字母l的个数:',field.count('l'))
列表field中,字母l的个数: 3
>>> print('列表field中,字母a的个数:',field.count('a'))
列表field中,字母a的个数: 0
>>> listobj=[123, 'hello', 'world', 123]
>>> listobj=[26, 'hello', 'world', 26]
>>> print('数字26 的个数:',listobj.count(26))
数字26 的个数: 2
>>> print('hello的个数:',listobj.count('hello'))#统计字符串个数
hello的个数: 1
>>> ['a','c','a','f','a'].count('a')
3
>>> mix=[[1,3],5,6,[1,3],2,]
>>> print('嵌套列表mix中列表[1,3]的个数为:',mix.count([1,3]))

嵌套列表mix中列表[1,3]的个数为:2

在实际项目应用中,count()方法用得比较少,是一个低频使用的方法。

12.高级排序

如果希望元素按特定方式进行排序(不是sort方法默认的按升序排列元素),就可以自定义比较方法。

sort方法有两个可选参数,即key和reverse。要使用它们,就要通过名字指定,我们称之为关键字参数。例如下面的示例:

>>> field=['study', 'python', 'is', 'happy']
>>> field.sort(key=len)                 #按字符串由短到长排序
>>> field
>>> field.sort(key=len, reverse=True)        #按字符串由长到短排序,传递两个参数
>>> field
['python', 'study', 'happy', 'is']
['is', 'study', 'happy', 'python']
>>> num=[5, 8, 1, 3, 6]
>>> num.sort(reverse=True)                 #排序后逆序
>>> num
[8, 6, 5, 3, 1]

由上面的操作结果可知,sort方法带上参数后的操作是很灵活的,可以根据自己的需要灵活使用该方法。关于自定义函数,后续章节会有更详细的介绍。

在实际项目应用中,高级排序应用的场景比较多,也各有特色,不同的项目会有不同的需求场景,需要视具体项目而定。