Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

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

最后修改:2025-02-01 08:59:27 GMT