PEP-3132 开宗明义,在Abstract 部分直接说道:
This PEP proposes a change to iterable unpacking syntax, allowing to specify a “catch-all” name which will be assigned a list of all items not assigned to a “regular” name.
翻译成中文就是:这个提案提议对可迭代对象解包语法进行修改,允许指定一个“catch-all”(我理解为“通吃”)名字,这个名字将在“常规”(“regular”)名字被赋值后接收所有剩下的元素。
一个示例胜过千言:
>>> a, *b, c = range(5)
>>> a
0
>>> c
4
>>> b
[1, 2, 3]
在提案的Rationale 部分,文章提到新的语法让以前类似first, rest = seq[0], seq[1:]
式子对序列(sequence)的拆解操作更加简洁,甚至可能更高效。那么,如果用新的语法,这个式子可以这么写:first, *rest = seq
在Specification 部分,文章指出一个出现在简单赋值式子左边的元组(tuple)或列表(list)最多只能包含一个带星号(*
)的表达式(文章把除星号表达式之外的表达式称为强制(mandatory)表达式)。星号表达式将在强制表达式被赋值完之后接收剩下的元素,星号表达式可能没有接收到元素,这时候它是一个空的列表。
如果seq
是一个有至少3个元素的可切片的序列,以下3个赋值操作都是等价的:
a, b, c = seq[0], list(seq[1:-1]), seq[-1]
a, *b, c = seq
[a, *b, c] = seq
星号表达式只能出现在元组或者列表中,单独出现在简单赋值表达式的左边会出现错误,例如*a = range(5)
,*a, = range(5)
或[*a] = range(5)
则是对的。而且在简单赋值式子左边出现的每一个强制表达式都要确保被赋值,如果式子右边的元素不够,也会导致错误。
这个提案也适用于在隐式赋值上下文中的元组,例如在for
语句:
for a, *b in [(1, 2, 3), (4, 5, 6, 7)]:
print(b)
结果会输出:
[2, 3]
[5, 6, 7]
文章的剩下部分超出了常用范围,就不讨论了。
在这里总结一下此提案的重点:
- 星号表达式作为赋值操作的对象必须出现在元组或者列表中
- 所以强制表达式都要被赋值
- 星号表达式可以为空列表