用 * 运算符把一个可迭代对象拆开作为函数的参数:
divmod(20, 8)
4
t = (20, 8)
divmod(*t)
4
quotient, remainder = divmod(*t)
quotient, remainder
4)
下面是另一个例子,这里元组拆包的用法则是让一个函数可以用元组的形式返回多个值,然
后调用函数的代码就能轻松地接受这些返回值。比如 os.path.split() 函数就会返回以
路径和最后一个文件名组成的元组 (path, last_part):>>> import os
>>> _, filename = os.path.split('/home/luciano/.ssh/idrsa.pub')
>>> filename
'idrsa.pub'
示例 2-9 展示了如何用具名元组来记录一个城市的信息。
示例 2-9 定义和使用具名元组
>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates') ➊
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667)) ➋
>>> tokyo
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722,
139.691667))
>>> tokyo.population ➌
36.933
>>> tokyo.coordinates
(35.689722, 139.691667)
>>> tokyo[1]
'JP'
❶ 创建一个具名元组需要两个参数,一个是类名,另一个是类的各个字段的名字。后者可
以是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串。
❷ 存放在对应字段里的数据要以一串参数的形式传入到构造函数中(注意,元组的构造函
数却只接受单一的可迭代对象)。
❸ 你可以通过字段名或者位置来获取一个字段的信息。
除了从普通元组那里继承来的属性之外,具名元组还有一些自己专有的属性。示例 2-10 中
就展示了几个最有用的:_fields 类属性、类方法 _make(iterable) 和实例方法
_asdict()。
如果在 a * n 这个语句中,序列 a 里的元素是对其他可变对象的引用的话,
你就需要格外注意了,因为这个式子的结果可能会出乎意料。比如,你想用 my_list
= [[]] * 3 来初始化一个由列表组成的列表,但是你得到的列表里包含的 3 个元素
其实是 3 个引用,而且这 3 个引用指向的都是同一个列表。这可能不是你想要的效果。
下面来看看如何用 * 来初始化一个由列表组成的列表。
接下来有个小例子,展示的是 *= 在可变和不可变序列上的作用:
>>> l = [1, 2, 3]
>>> id(l)
4311953800 ➊
>>> l *= 2
>>> l
[1, 2, 3, 1, 2, 3]
>>> id(l)
4311953800 ➋
>>> t = (1, 2, 3)
>>> id(t)
4312681568 ➌
>>> t *= 2
>>> id(t)
4301348296 ➍
❶ 刚开始时列表的 ID。
❷ 运用增量乘法后,列表的 ID 没变,新元素追加到列表上。
❸ 元组最开始的 ID。
❹ 运用增量乘法后,新的元组被创建。对不可变序列进行重复拼接操作的话,效率会很低,因为每次都有一个新对象,而解释器需
要把原来对象中的元素先复制到新的对象里,然后再追加新的元素。 4
4 str
是一个例外,因为对字符串做 += 实在是太普遍了,所以 CPython 对它做了优化。为 str 初始化内存的时候,程序
会为它留出额外的可扩展空间,因此进行增量操作的时候,并不会涉及复制原有字符串到新位置这类操作。