11 Python列表和元组

列表:

前面已经用了很多次列表,可以看出列表的功能是比较强大的。本节将讨论列表不同于元组和字符串的地方:列表的内容是可变的(mutable)。列表有很多比较好用、比较独特的方法,将一一进行介绍。
本篇将介绍一些序列中没有而列表中有的方法,这些方法的作用都是更新列表,有元素赋值、元素删除、分片赋值和列表方法。下面逐一进行介绍。

1.元素赋值

我们前面学习过赋值语句,赋值语句是最简单地改变列表的方式,如a=2就是一种改变列表的方式。这里我们将通过编号标记某个特定位置的元素,并对该位置的元素重新赋值,如a[1]=10。在交互模式输入如下:

>>> a=[1,2,3,2,1]
>>> a[1]=10
>>> a
[1, 10, 3, 2, 1]
>>> a[3]=10
>>> a
[1, 10, 3, 10, 1]

还记得我们的编号是从0开始吧!
从上面的输出结果可以得知,我们可以根据编号对列表中某个元素重新赋值。既然可以重新赋值,是否可以赋不同类型的值呢?我们尝试一下,输入如下:

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

由上面的输出结果可以得知,可以对一个列表中的元素赋不同类型的值。比如上面的示例,列表a中既有int类型的值,也有str类型的值。
假如对列表赋值时使用的编号超过了列表中的最大编号,是否还可以赋值呢?我们尝试一下,输入如下:

>>> tring=[1,2,3]
>>> tring[3]='test'
Traceback (most recent call last):
  File "<pyshell#43>", line 1, in <module>
  tring[3]='test'
IndexError: list assignment index out of 

在上面的示例中,tring的最大编号是2,当给编号为3的元素赋值时就会出错。由此得知:不能为一个不存在元素的位置赋值。如果一定要赋值,前面学习的序列通用操作中的乘法可以帮助我们,输入如下:

>>> tring=[None]*5
>>> tring[3]='test'
>>> tring
[None, None, None, 'test', None]

由以上输出结果可以得知,可以对初始化过的位置进行赋值。
注意:不能为一个不存在元素的位置赋值。

2.增加元素

由元素赋值的示例可以看到,不能为一个不存在的位置赋值。一旦初始化了一个列表,就不能再往这个列表中增加元素了。若需要往列表中增加元素,则需要将整个列表中的元素都复制一遍,再添加需要增加的元素。Python中是否提供了对应的方法帮助我们做这件事情呢?答案是肯定的。输入如下:

>>> tring=[1,2,3]
>>> tring.append(4)
>>> tring
[1, 2, 3, 4]

由示例看到,可以使用append()方法解决前面的困惑。append()方法是一个用于在列表末尾添加新对象的方法。该方法的语法如下:

list.append(obj)

此语法中list代表列表,obj代表需要添加到list列表末尾的对象。
注意:append的使用方式是list.append(obj)。
由前面的输出结果得知:append()方法不是简单地返回一个修改过的新列表,而是直接修改原来的列表。下面展示几个append()的示例:

>>> tring=[1,2,3]
>>> tring.append('test')  #添加字符串
>>> tring
[1, 2, 3, 'test']
>>> s=['a','b','c']
>>> s.append(3)           #添加数字
>>> s
['a', 'b', 'c', 3]

由上面的示例可以得知:可以往数字序列中添加字符串,也可以往字符串序列中添加数字。

3.删除元素

前面学习了往列表中增加元素,是否可以在列表中删除元素呢?例如下面的示例:

>>> tring=['a','b','c','d','e']
>>> len(tring)
5
>>> del tring[1]
>>> print('删除第二个元素:',tring)
删除第二个元素: ['a', 'c', 'd', 'e']
>>> len(tring)
4

由上面的示例看到,可以使用del删除列表中的元素。上面的示例使用del删除了tring列表中的第二个元素,删除元素后,原来有5个元素的列表变成只有4个元素的列表了。使用del除了可以删除列表中的字符,也可以删除列表中的数字,输入如下:

>>> num=[1,2,3]
>>> len(num)
3
>>> del num[2]
>>> print('删除第3 个元素后:',num)
删除第3 个元素后:[1, 2]
>>> len(num)
2

上面的输出结果已经从数字列表中删除了对应的数字。
除了删除列表中的元素,del还能用于删除其他元素,具体在后续章节会做详细介绍。

4.分片赋值

分片赋值是列表一个强大的特性。先看下面的示例:

>>> list('女排夺冠了')
['女', '排', '夺', '冠', '了']
>>> boil=list('女排夺冠了')
>>> boil
['女', '排', '夺', '冠', '了']
>>> show=list('hi,boy')
>>> show
['h', 'i', ',', 'b', 'o', 'y']
>>> show[3:]=list('man')
>>> show
['h', 'i', ',', 'm', 'a', 'n']

由上述示例可以看出,可以通过分片赋值直接对列表进行变更。示例中我们通过分片操作变更了编号3之后位置的元素,即将boy替换为man了。
上述示例中引入了一个新函数——list()函数。list()函数可以直接将字符串转换为列表。该函数的一个功能就是根据字符串创建列表,有时这么操作会很方便。List()函数不仅适用于字符串,所有类型的序列它都适用。
除了上面展示的功能,分片赋值还有什么强大的功能呢?先看下面的示例:

>>> 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']
>>> boil=list('女排夺冠了')
>>> boil
['女', '排', '夺', '冠', '了']
>>> boil[2:2]=list('2016 年奥运会')
>>> boil
['女', '排', '2', '0', '1', '6', '年', '奥', '运', '会', '夺', '冠', '了']

从上面的示例可以看出,可以在不替换任何原有元素的情况下在任意位置插入新元素。读者可自行尝试在上面示例的其他位置进行操作。
当然,上面的示例程序只是“替换”了一个空分片,实际操作是插入一个序列。
通过该示例是否想起了前面的append()方法,不过分片赋值比append()方法强大多了,append()方法只能在列表尾部增加元素,而分片赋值可以在任意位置增加元素。
看到这里,是否同时想起了前面删除元素的操作,分片赋值是否支持类似删除的功能呢?是的,支持类似删除的功能。下面我们证实一下这个猜想。

>>> field=list('abcde')
>>> field
['a', 'b', 'c', 'd', 'e']
>>> field[1:4]=[]
>>> field
['a', 'e']
>>> boil=list('女排2016 年奥运会夺冠了')
>>> boil
['女', '排', '2', '0', '1', '6', '年', '奥', '运', '会', '夺', '冠', '了']
>>> boil[2:10]=[]
>>> boil
['女', '排', '夺', '冠', '了']
>>> del field[1:4]
>>> field
['a', 'e']

从上面示例可以看到,使用了前面插入操作的逆操作证实我们的猜想。删除和插入一样,可以对一个序列中任意位置的元素进行删除。
所以通过分片赋值删除元素也是可行的,并且分片赋值删除的功能和del删除的操作结果是一样的。

5.嵌套列表

前面介绍的都是单层的列表,列表是否可以嵌套呢?我们做如下尝试:

>>> field=['a','b','c']
>>> field
['a', 'b', 'c']
>>> num=[1,2,3]
>>> num
[1, 2, 3]
>>> mix=[field,num]
>>> mix
[['a', 'b', 'c'], [1, 2, 3]]
>>> mix[0]
['a', 'b', 'c']
>>> mix[1]
[1, 2, 3]

由上面的操作结果得知,在列表中可以嵌套列表,嵌套的列表取出后还是列表。

列表方法

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

对象.方法(参数)

由上面的语法和前面append()方法的示例可知:方法的定义方式是将对象放到方法名之前,两者之间用一个点号隔开,方法后面的括号中可以根据需要带上参数。除了语法上有一些不同,方法调用和函数调用很相似。
列表中有count、index、sort等比较常用的方法,下面逐一进行介绍。

1. append

该方法前面已经介绍过,功能是在列表的末尾添加新对象。
使用方式为:

list.append(obj)
2. count

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

list.count(obj)

此语法中list代表列表,obj代表列表中统计的对象。
使用该方法的示例如下:

>>> 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
3. extend

extend()方法用于在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)。
extend()方法的语法如下:

list.extend(seq)

此语法中list代表列表,seq代表元素列表。
使用该方法的示例如下:

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

以上操作结果看起来很像连接操作。extend()方法和序列相加有什么区别呢?我们先看看下面的示例:

>>> a=['hello','world']
>>> b=['python','is','funny']
>>> a+b
['hello', 'world', 'python', 'is', 'funny']
>>> a
['hello', 'world']

从输出的结果可以看出,两个示例中a和b赋值都是一样的,但第一个示例中输出a的值和第二个示例中输出a的值不一样。
由此我们得出,extend()方法和序列相加的主要区别是:extend()方法修改了被扩展的序列,如前面的a;原始的连接操作会返回一个全新的列表,如上面的示例,返回的是一个包含a和b副本的新列表,而不会修改原始的变量。
当然,上述示例也可以用前面学习的分片赋值实现相同的结果,输入如下:

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

可以看到,输出结果和使用extend()方法一样,不过看起来没有extend()方法易懂,因此不会选择这个方案。

4. index

index()方法用于从列表中找出某个值第一个匹配项的索引位置。index()方法的语法如下:

list.index(obj)

此语法中list代表列表,obj代表查找的对象。
使用该方法的示例如下:

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

由上面的示例看到,搜索单词hello,会发现它在索引号为0的位置;搜索单词python,它在索引号为2的位置,索引得到的位置跟元素在序列中的位置一样。如果搜索列表中不存在字符串,操作结果就会出错,所以对于不在列表中的元素,用index()方法操作时会报错。

5. insert

insert()方法用于从列表中找出某个值第一个匹配项的索引位置。
insert()方法的语法如下:

list.insert(index,obj)

此语法中list代表列表,index代表对象obj需要插入的索引位置,obj代表要插入列表中的对象。
使用该方法的示例如下:

>>> num=[1,2,3]
>>> print('插入之前的num:',num)
插入之前的num: [1, 2, 3]
>>> num.insert(2,'插入位置在2 之后,3 之前')
>>> print('插入之后的num:',num)
插入之后的num:[1, 2, '插入位置在2 之后,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 之前']

输出结果和insert操作的结果一样,但看起来没有使用insert容易理解,应该不会选择这个方案。

6. pop

pop()方法用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。
pop()方法的语法如下:

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

此语法中list代表列表,obj为可选择的参数,代表要移除列表元素的对象。
使用该方法的示例如下:

>>> 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。移除funny时未传参数,默认移除最后一个;is的移除则是根据传入的编号3进行的。
注意: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]

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

7. remove

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

list.remove(obj)

此语法中list代表列表,obj为列表中要移除的对象。
使用该方法的示例如下:

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

由上面的输出结果看到,只有第一次出现的值被移除了,第二次之后出现的值没有被移除。上面的列表中有3个“精神”,调用移除方法后,删除了第一个,后面两个仍然存在。
同时,操作移除列表中不存在的值是不行的,系统会告知移除的对象不在列表中。
有一点需要了解的是:remove是一个没有返回值的原位置元素变更方法,它修改了列表却没有返回值,与pop方法正好相反。

8. reverse

reverse()方法用于反向列表中的元素。
reverse()方法的语法如下:

list.reverse()

此语法中list代表列表,该方法不需要传入参数。
使用该方法的示例如下:

>>> 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]

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

9. sort

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

list.sort(func)

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

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

由上面输出的结果得知,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,但是返回的是空值,所以我们最后得到的是已排序的num和值为None的n。该想法正确的实现方式是先把num的副本赋值给n,然后对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),则两个列表都会被排序,这样简单的赋值后,两个列表都指向同一个列表。由此提醒进行该操作时要记得对原列表分片。
如reverse方法一样,sort方法也有一个有同样功能的函数——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']
10. clear

clear()方法用于清空列表,类似于dela[:]。
clear()方法的语法如下:

list.clear()

此语法中list代表列表,不需要传入参数。
使用该方法的示例如下:

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

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

11. copy

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

list.copy()

此语法中list代表列表,不需要传入参数。
使用该方法的示例如下:

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

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

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方法带上参数后的操作是很灵活的,可以根据自己的需要灵活使用该方法。关于自定义函数,后续章节会有更详细的介绍。

元组:

Python的元组与列表类似,不同之处在于元组的元素不能修改(前面多次提到的字符串也是不能修改的)。创建元组的方法很简单:如果你使用逗号分隔了一些值,就会自动创建元组。
例如,我们如下输入:

>>> 1,2,3
(1, 2, 3)
>>> 'hello','world'
('hello', 'world')

上面的操作用逗号分隔了一些值,结果输出的是元组。
我们经常使用圆括号将值括起来,例如:

>>> (1, 2, 3)
(1, 2, 3)
>>> ('hello', 'world')
('hello', 'world')

还可以创建空元组,操作如下:

>>> ()
()

如果圆括号中不包含任何内容,就是一个空元组。
创建包含一个值的元组如何实现呢?可以进行如下尝试:

>>> (1)
1

输出结果不是元组,包含一个值的元组的实现方式有一些奇特,必须在括号中的元素后加一个逗号,例如:

>>> (1,)
(1,)

由上面的示例看到,逗号很重要,只添加括号是没有用的。
下面我们介绍元组的相关操作。

tuple函数

tuple函数的功能和list函数基本上一样,都是以一个序列作为参数,并把它转换为元组。如果参数是元组,参数就会被原样返回,例如:

>>> tuple(['hello','world'])
('hello', 'world')
>>> tuple('hello')
('h', 'e', 'l', 'l', 'o')
>>> tuple(('hello','world')) #参数是元组
('hello', 'world')

由上面的操作看到,tuple函数传入元组参数后,得到的返回值就是传入的参数。

元组的基本操作

和列表一样,元组也有一些基本操作,如访问元组、修改元组、删除元组、索引和截取等操作。当然,这里的修改、删除和截取等操作和列表的操作不太一样。

1. 访问元组

可以使用下标索引访问元组中的值,例如:

>>> mix = ('hello', 'world', 2015, 2016)
>>> print ("mix[1] is: ", mix[1])
mix[1] is: world
>>> num = (1, 2, 3, 4, 5, 6, 7 )
>>> print ("num[1:5] is: ", num[1:5])
num[1:5] is: (2, 3, 4, 5)
2. 修改元组

元组中的元素值不允许修改,但可以对元组进行连接组合,例如:

>>> field = ('hello', 'world')
>>> num = (2015, 2016)
>>> print ("合并结果为: ", field+num)
合并结果为:   ('hello', 'world', 2015, 2016)
3. 删除元组

元组中的元素值不允许删除,但可以使用del语句删除整个元组,例如:

>>> field = ('hello', 'world')
>>> del field
>>> print('删除后的结果:',field)
Traceback (most recent call last):
  File "<pyshell#84>", line 1, in <module>
    print('删除后的结果:',field)
NameError: name 'field' is not defined

以上实例的元组被删除后,输出变量会有异常信息,输出结果告诉我们field没有定义,即field已经不存在了。

4. 元组索引、截取

因为元组也是一个序列,所以可以访问元组中指定位置的元素,也可以截取索引中的一段元素,例如:

>>> field = ('hello', 'world', 'welcome')
>>> field [2]
'welcome'
>>> field [-2]
'world'
>>> field [1:]
('world', 'welcome')

元组内置函数

Python元组提供了一些内置函数,如计算元素个数、返回最大值、返回最小值、列表转换等函数。
len(tuple)用于计算元组元素个数。使用方式如下:

>>> tup = ('hello', 'world', 'welcome')
>>> len(tup)
3

max(tuple)用于返回元组中元素的最大值。使用方式如下:

>>> tup = ('6', '3', '8')
>>> max(tup)
'8'

min(tuple)用于返回元组中元素的最小值。使用方式如下:

>>> tup = ('6', '3', '8')
>>> min(tup)
'3'

tuple(seq)用于将列表转换为元组。使用方式如下:

>>> field= ['hello', 'world', 'welcome']
>>> tup=tuple(field)
>>> tup
('hello', 'world', 'welcome')

以上为Python中常见的一些元组的内置函数,大家可以自行操作其他函数尝试。

列表与元组的区别

列表与元组的区别在于元组的元素不能修改,元组一旦初始化就不能修改。
不可变的元组有什么意义?因为元组不可变,所以代码更安全。如果可能,能用元组代替列表就尽量用元组。我们看下面的示例:

>>> t = ('a', 'b', ['A', 'B'])
>>> t[2][0] = 'X'
>>> t[2][1] = 'Y'
>>> t
('a', 'b', ['X', 'Y'])

此处使用了嵌套列表,一个列表中包含另一个列表,也可以称为二维数组。一个单一的列表称为一维数组,还有三维、四维等多维数组,不过一般一维和二维数组用得最多,三维以上的数组基本很少用到。
取二维数组中元素的方式为:先取得二维数组里嵌套的数组,如上例中的t[2],取得的是['A', 'B'],t[2]是一个一维数组,从一维数组中获取元素是以a[0]的方式获取的,因而从t[2]中取得编号为0的元素的方式是t[2][0]。
上面的元组定义时有3个元素,分别是'a'、'b'和一个list列表。不是说元组一旦定义就不可变了吗?怎么后来又变了?
别急,我们先看看定义时元组包含的3个元素,如图1所示。
当我们把list列表的元素'A'和'B'修改为'X'和'Y'后,元组如图2所示。


1-元组定义

2-元组“修改”

表面上看,元组的元素确实变了,其实变的不是元组的元素,而是list列表的元素。元组一开始指向的list列表并没有改成别的list列表,所以元组的“不变”是指每个元素的指向永远不变,如指向'a'就不能改成指向'b',指向一个list就不能改成指向其他对象,但指向的list列表本身是可变的。
理解了“指向不变”后,创建一个内容不变的tuple要怎么做?这时必须保证tuple的每一个元素本身也不能变。

调试

这里通过设置的一些错误让读者认识在编写代码过程中的常见问题,以帮助读者熟悉和解决实际遇到的问题。
(1)对序列中的元素进行访问时,输入序列中不存在的编号,如在greeting='Hello'示例中输入greeting[10],会得到什么结果?输入greeting[-10]又会得到什么结果?在交互模式下进行验证:

>>> greeting='hello'
>>> len(greeting) #获取字符串长度
5
>>> greeting[10]   #编号超过最大长度编号
Traceback (most recent call last):
  File "<pyshell#92>", line 1, in <module>
    greeting[10]
IndexError: string index out of range
>>> greeting[5] #字符串长度为5,但最大编号不是5
Traceback (most recent call last):
  File "<pyshell#97>", line 1, in <module>
    greeting[5]
IndexError: string index out of range
>>> greeting[len(greeting)-1] #最大编号是字符串长度减1
'o'
>>> greeting[-10]
Traceback (most recent call last):
  File "<pyshell#95>", line 1, in <module>
    greeting[-10]
IndexError: string index out of range
>>> greeting[-1]
'o'
>>> greeting[-5]
'h'

从以上输出结果看出,以正数索引时,编号从0开始,最后一个元素的编号是len(str)-1;以负数索引时,从-1开始,可以取到-len(str)的元素。
当索引超出范围时,Python会报一个IndexError错误,即索引越界错误。要确保索引不越界,记得最后一个元素的索引是len(str) - 1。
(2)分片操作中,索引值大于列表的最大编号时,操作会报错吗?结果是怎样的?在交互模式输入如下:

>>> number=[1,2,3,4,5,6,7,8,9,10]
>>> number[7:15]
[8, 9, 10]
>>> number[-100:-1]
[1, 2, 3, 4, 5, 6, 7, 8, 9] #最后一个元素没有取到

由以上操作结果看到没有报错,并且超出部分没有输出任何内容。这里要声明一点:分片操作不存在索引越界的问题,分片操作对不存在的编号返回空值,存在的就返回对应值。所以number[7:15]返回[8, 9, 10],number[-100:-1]返回[1, 2, 3, 4, 5, 6, 7, 8, 9]。
(3)输入以下代码会得到什么结果?

>>> max(a,b,c)
Traceback (most recent call last):
  File "<pyshell#114>", line 1, in <module>
    max(a,b,c)
NameError: name 'a' is not defined
>>> max('a','b','c')
'c'

第一个输出错误信息,因为a、b、c没有定义,这个操作要注意字符串的表示形式。第二个输出结果为c,max不但能操作数字,而且能操作字符,字符按字典排序取值。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容