PEP 3132 – 扩展的可迭代解包
- 作者:
- Georg Brandl <georg at python.org>
- 状态:
- 最终
- 类型:
- 标准跟踪
- 创建:
- 2007年4月30日
- Python 版本:
- 3.0
- 历史记录:
摘要
本 PEP 提出更改可迭代解包语法,允许指定一个“捕获所有”名称,该名称将被分配一个包含所有未分配给“常规”名称的项的列表。
一个例子胜过千言万语
>>> a, *b, c = range(5)
>>> a
0
>>> c
4
>>> b
[1, 2, 3]
基本原理
许多算法需要将序列拆分为“第一个,其余”对。使用新的语法,
first, rest = seq[0], seq[1:]
被更简洁、可能更高效的替换为
first, *rest = seq
对于更复杂的解包模式,新语法看起来更加简洁,并且不再需要笨拙的索引处理。
此外,如果右侧的值不是列表,而是一个可迭代对象,则必须将其转换为列表才能进行切片;为了避免创建此临时列表,必须诉诸于
it = iter(seq)
first = it.next()
rest = list(it)
规范
简单赋值左侧的元组(或列表)(解包未为增强赋值定义)最多可以包含一个以单个星号开头的表达式(此后称为“星号”表达式,而列表中的其他表达式称为“必需”)。这指定了一个子表达式,该子表达式将被分配一个列表,其中包含来自被解包的可迭代对象的所有未分配给任何必需表达式的项,或者如果不存在此类项,则为空列表。
例如,如果seq
是可切片的序列,则如果seq
至少有两个元素,则以下所有赋值都是等效的
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)
请注意,此提案也适用于隐式赋值上下文中的元组,例如在for
语句中
for a, *b in [(1, 2, 3), (4, 5, 6, 7)]:
print(b)
将打印出
[2, 3]
[5, 6, 7]
星号表达式仅允许用作赋值目标,在其他任何地方使用它们(当然,函数调用中的星号参数除外)都是错误的。
实现
语法更改
此功能需要一个新的语法规则
star_expr: ['*'] expr
在这两个规则中,expr
更改为star_expr
comparison: star_expr (comp_op star_expr)*
exprlist: star_expr (',' star_expr)* [',']
编译器更改
添加了一个新的 ASDL 表达式类型Starred
,它表示星号表达式。请注意,此处引入的星号表达式元素是通用的,以后可以在非赋值上下文中用于其他目的,例如yield *iterable
提案。
编译器已更改为识别星号表达式无效的所有情况,并使用语法错误对其进行标记。
添加了一个新的字节码指令UNPACK_EX
,其参数在低 8 位中具有星号目标之前必需目标的数量,在高 8 位中具有星号目标之后必需目标的数量。对于没有星号表达式的解包序列,保留旧的UNPACK_ITERABLE
操作码。
字节码解释器更改
ceval.c 中的unpack_iterable()
函数已更改为通过argcntafter
参数处理扩展解包。在UNPACK_EX
情况下,该函数将执行以下操作
- 收集星号目标之前所有必需目标的项
- 将可迭代对象中的所有剩余项收集到列表中
- 从列表中弹出星号目标之后必需目标的项
- 将单个项和调整大小的列表推送到堆栈上
可以添加用于解包已知类型的可迭代对象(例如列表或元组)的快捷方式。
当前实现可以在 SourceForge Patch 跟踪器[SFPATCH]中找到。它现在包含一个最小的测试用例。
接受
在 python-3000 列表上进行简短讨论[1]后,Guido 以其当前形式接受了 PEP。讨论的可能更改包括
- 仅允许星号表达式作为 exprlist 中的最后一项。这将稍微简化解包代码,并允许将星号表达式分配给迭代器。此行为被拒绝,因为它过于令人意外。
- 尝试使星号目标与源可迭代对象具有相同的类型,例如,
b
在a, *b = 'hello'
中将被分配字符串'ello'
。这似乎很好,但无法与所有可迭代对象保持一致。 - 使星号目标成为元组而不是列表。这将与函数的
*args
保持一致,但会使结果的进一步处理变得更加困难。
参考文献
版权
本文件已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-3132.rst