个人总结难免疏漏,请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。
目录
元组
元组操作
实际应用
元组的特殊语法:逗号和圆括号
转换、方法以及不可变性
index、count及其他方法
有了列表为什么还要元组
元组
元组(tuple)由简单的对象组构成。元组与列表非常类似,只不过元组不能在原处修改(它们是不可变的),并且通常写成圆括号(而不是方括号)中的一系列项。
元组不支持任何方法调用,但元组具有列表的大多数属性。
任意对象的有序集合
与字符串和列表类似,元组是一个位置有序的对象的集合(也就是其内容维持从左到右的顺序)。与列表相同,可以嵌入到任何类别的对象中。
通过偏移存取
同字符串、列表一样,在元组中的元素通过偏移(而不是键)来访问。它们支持所有基于偏移的操作。例如,索引和分片。
属于不可变序列类型
类似于字符串,元组是不可变的,它们不支持应用在列表中任何原处修改操作。与字符串和列表类似,元组是序列,它们支持许多同样的操作。
固定长度、异构、任意嵌套
元组是不可变的,在不生成一个拷贝的情况下不能增长或缩短。另一方面,元组可以包含其他的复合对象(例如,列表、字典和其他元组等)
对象引用的数组
与列表相似,元组最好看做是对象引用的数组。元组存储指向其他对象的存取点(引用),并且对元组进行索引操作的速度相对较快。
元组操作
元组编写为一系列对象(从技术上来讲,是生成对象的表达式),用逗号隔开,并且用圆括号括起来。一个空元组就是一对内空的括号。
实际应用
在表9-1中,元组没有方法(例如,append调用在这是不可用的)。然而,元组的确支持字符串和列表的一般序列操作。
>>> (1,2) + (3,4)
(1, 2, 3, 4)
>>> (1,2) * 4
(1, 2, 1, 2, 1, 2, 1, 2)
>>> t = (1,2,3,4)
>>> t[0],t[1:3]
(1, (2, 3))
元组的特殊语法:逗号和圆括号
如果圆括号里的单一对象是元组对象而不是一个简单的表达式,需要对Python进行特别说明。如果确实想得到一个元组,只要在这一单个元素之后、关闭圆括号之前加一个逗号就可以了。
作为特殊情况,在不会引起语法冲突的情况下,Python允许忽略元组的圆括号。
>>> x = 40
>>> x
40
>>> type(x)
<class 'int'>
>>> y = 40,
>>> y
(40,)
>>> type(y)
<class 'tuple'>
>>> z = (40,)
>>> z
(40,)
>>> type(z)
<class 'tuple'>
对初学者而言,最好的建议是一直使用圆括号,这可能会比弄明白什么时候可以省略圆括号要更简单一些。许多程序员也发现圆括号有助于增加脚本的可读性,因为这样可以使元组更加明确,尽管你的使用经验可能会有所不同。
转换、方法以及不可变性
除了常量语法不同以外,元组的操作(表9-1的中间行)和字符串及列表是一致的。值得注意的区别在于“+”、“*”以及分片操作应用于元组时将返回新元组,并且元组不提供字符串、列表和字典中的方法。
例如,如果你想对元组进行排序,通常先得将它转换为列表并使其成为一个可变对象,才能获得使用排序方法调用的权限,或者使用sorted内置方法,它接受任何序列对象(以及更多):
>>> t = ('a','z','c','b')
>>> tmp = list(t)
>>> tmp
['a', 'z', 'c', 'b']
>>> tmp.sort()
>>> tmp
['a', 'b', 'c', 'z']
>>> tu = tuple(tmp)
>>> tu
('a', 'b', 'c', 'z')
>>> sorted(t)
['a', 'b', 'c', 'z']
>>> t
('a', 'z', 'c', 'b')
这里的列表和元组内置函数用来将对象转换为列表,之后返回为一个元组。实际上,这两个调用都会生成新的对象,但结果就像是转换。
列表解析(List comprehension)也可用于元组的转换。
例如,下面这个由元组生成的列表,过程中将每一项都加上20:
>>> t1 = (1,2,3)
>>> l1 = [x + 20 for x in t1]
>>> l1
[21, 22, 23]
列表解析是名副其实的序列操作——它们总会创建新的列表,但也可以用于遍历包括元组、字符串以及其他列表在内的任何序列对象。
列表解析甚至可以用在某些并非实际储存的序列之上——任何可遍历的对象都可以,包括可自动逐行读取的文件。
注意元组的不可变性只适用于元组本身顶层而并非其内容。例如,元组内部的列表是可以像往常那样修改的。
>>> t[1] = 'a'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t[1][0] = 'a'
>>> t
(1, ['a', 3], 4)
对多数程序而言,这种单层深度的不可变性对一般元组角色来说已经足够了。
index、count及其他方法
index和count就像对列表一样工作,但是,它们也针对元组对象定义了:
>>> t2 = (1,2,3,4,5,11,22,33,1,2)
>>> t2.index(1) #查询出第一次出现的偏移量
0
>>> t2.index(33)
7
>>> t2.index(2,2) #查询出第二次出现的偏移量
9
>>> t2.index(33,2)
7
>>> t2.index(33,3)
7
>>> t2.index(1,2)
8
>>> t2.count(1) #统计总数
2
>>> t2.count(33)
1
>>> t2
(1, 2, 3, 4, 5, 11, 22, 33, 1, 2)
>>> len(t2) #长度
10
>>> min(t2) #最小
1
>>> max(t2) #最大
33
>>> del t2 #删除
>>> t2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 't2' is not defined
有了列表为什么还要元组
初学者学习元组的时候,这似乎总是第一个出现的问题——既然已经有列表了,为什么还需要元组?
历史性原因是:Python的创造者接受过数学训练,并提到过把元组看做是简单的对象组合,把列表看成是随时间改变的数据结构。实际上,单词“元组”就借用自数学领域,它通常用来指关系数据库表的一行。
最佳答案似乎是元组的不可变性提供了某种完整性。这样你可以确保元组在程序中不会被另一个引用修改,而列表就没有这样的保证了。
元组的角色类似于其他语言中的“常数”声明,然而这种常数概念在Python中是与对象相结合的,而不是变量。
元组也可以用在列表无法使用的地方。例如,作为字典键。一些内置操作可能也要求或暗示要使用元组而不是列表,尽管这样的操作往往已经通用化了。
总的来说:列表是定序集合的选择工具,可能需要进行修改,而元组能够处理其他固定关系的情况。