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 中的最后一项。这将稍微简化解包代码,并允许将迭代器分配给带星号的表达式。此行为被拒绝,因为它会过于令人惊讶。
- 尝试使带星号的目标具有与源可迭代对象相同的类型,例如,
a, *b = 'hello'中的b将被赋值为字符串'ello'。这可能看起来不错,但不可能与所有可迭代对象保持一致。 - 将带星号的目标设为元组而不是列表。这将与函数的
*args一致,但会使结果的进一步处理变得更困难。
参考资料
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-3132.rst