元组
定义
- 元组是一种序列类型,一旦创建就不能被修改;
- 使用小括号 () 或 tuple() 创建,元素间用逗号 , 分隔可以使用或不使用小括号
- 函数中返回的多个值本质为返回元组类型 def func(): return 1,2
- 元组继承了序列类型的全部通用操作。元组因为创建后不能修改,因此没有特殊操作
- 只有1个元素的tuple定义时必须加一个逗号,,来消除歧义:t = (1,)
- tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple:
>>> (0, 1, 2, 3, 4, 5)[:3]
(0, 1, 2)
1
2
2
tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。
>>> t = ('a', 'b', ['A', 'B'])
>>> t[2][0] = 'X'
>>> t[2][1] = 'Y'
>>> t
('a', 'b', ['X', 'Y'])
1
2
3
4
5
2
3
4
5
当我们把list的元素'A'和'B'修改为'X'和'Y'后,tuple变为:
元组拆包
元组拆包可以应用到任何可迭代对象上,唯一的硬性要求是,被可迭代对象中的元素数量必须要跟接受这些元素的元组的空档数一致。除非我们用 * 来表示忽略多余的元素。
平行赋值
把一个可迭代对象里的元素,一并赋值到由对应的变量组成的元组中。
lax_coordinates = (33.9425, -118.408056)
latitude, longitude = lax_coordinates # 元组拆包
>>> latitude
33.9425
>>> longitude
-118.408056
#另外一个很优雅的写法当属不使用中间变量交换两个变量的值:
b, a = a, b
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
还可以用 * 运算符把一个可迭代对象拆开作为函数的参数:
>>> divmod(20, 8)
(2, 4)
>>> t = (20, 8)
>>> divmod(*t)
(2, 4)
>>> quotient, remainder = divmod(*t)
>>> quotient, remainder
(2, 4)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
用来处理剩下的元素。在平行赋值中, 前缀只能用在一个变量名前面,但是这个变量可以出现在赋值表达式的任意位置:
>>> a, *body, c, d = range(5)
>>> a, body, c, d
(0, [1, 2], 3, 4)
>>> *head, b, c, d = range(5)
>>> head, b, c, d
([0, 1], 2, 3, 4)
1
2
3
4
5
6
2
3
4
5
6
嵌套元组拆包
接受表达式的元组可以是嵌套式的,例如 (a, b, (c, d))。
这里有一个非常值得探讨的问题,我们已经有了列表这种数据结构,为什么还需要元组这样的类型呢?
- 元组中的元素是无法修改的,事实上我们在项目中尤其是多线程 (opens new window)环境(后面会讲到)中可能更喜欢使用的是那些不变对象(一方面因为对象状态不能修改,所以可以避免由此引起的不必要的程序错误,简单的说就是一个不变的对象要比可变的对象更加容易维护;另一方面因为没有任何一个线程能够修改不变对象的内部状态,一个不变对象自动就是线程安全的,这样就可以省掉处理同步化的开销。一个不变对象可以方便的被共享访问)。所以结论就是:如果不需要对元素进行添加、删除、修改的时候,可以考虑使用元组,当然如果一个方法要返回多个值,使用元组也是不错的选择。
- 元组在创建时间和占用的空间上面都优于列表。我们可以使用sys模块的getsizeof函数来检查存储同样的元素的元组和列表各自占用了多少内存空间,这个很容易做到。我们也可以在ipython中使用魔法指令%timeit来分析创建同样内容的元组和列表所花费的时间,下图是我的macOS系统上测试的结果。
上次更新: 2025/04/02, 12:03:38