有没有办法在解包时将 splat-assign 分配为元组而不是列表?

App*_*ish 12 python tuples list python-3.x iterable-unpacking

我最近惊讶地发现“splat”(一元 *)运算符总是list在项目解包期间将切片捕获为 a ,即使被解包的序列具有另一种类型:

>>> x, *y, z = tuple(range(5))
>>> y
[1, 2, 3]  # list, was expecting tuple
Run Code Online (Sandbox Code Playgroud)

与不拆包的情况下如何编写此作业进行比较:

>>> my_tuple = tuple(range(5))
>>> x = my_tuple[0]
>>> y = my_tuple[1:-1]
>>> z = my_tuple[-1]
>>> y
(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)

它也与 splat 运算符在函数参数中的行为方式不一致:

>>> def f(*args):
...     return args, type(args)
...
>>> f()
((), <class 'tuple'>)
Run Code Online (Sandbox Code Playgroud)

为了y在解包后恢复为元组,我现在必须写:

>>> x, *y, z = tuple(range(5))
>>> y = tuple(y)
Run Code Online (Sandbox Code Playgroud)

这仍然比基于切片的语法好得多,但仍然受到我认为非常不必要和意外的优雅损失的影响。有没有办法在y没有分配后处理的情况下恢复为元组而不是列表?

我试图y通过写入来强制 python 解释为一个元组x, *(*y,), z = ...,但它最终仍然是一个列表。当然,像x, *tuple(y), z 在 python 中不起作用这样的愚蠢事情。

我目前正在使用 Python 3.8.3,但也欢迎涉及更高版本(可用时)的解决方案/建议/解释。

pro*_*ico 5

这是设计使然。引用有关分配的官方文档:

...迭代的第一项从左到右分配给加星标目标之前的目标。可迭代对象的最后一项被分配给加星标的目标之后的目标。然后将迭代中剩余项目的列表分配给加星标的目标(该列表可以为空)。

Python 用户很可能想在y之后改变你的,所以list类型是在tuple.

引用我通过相关问题中的链接找到的PEP 3132的接受部分:

在对 python-3000 列表 [1] 进行了简短讨论后,Guido 接受了当前形式的 PEP。讨论的可能变化是:

  • 只允许带星号的表达式作为 exprlist 中的最后一项。这将稍微简化解包代码,并允许为带星号的表达式分配一个迭代器。这种行为被拒绝了,因为这太令人惊讶了。

  • 尝试为加星标的目标提供与源可迭代对象相同的类型,例如, b ina, *b = "hello"将被分配字符串"ello"。这可能看起来不错,但不可能与所有可迭代对象保持一致。

  • 使加星标的目标成为元组而不是列表。这将与函数的 一致*args,但会使结果的进一步处理更加困难。

所以y = tuple(y)之后转换是你唯一的选择。

  • 是的,此链接包含我正在寻找的解释。如果您用最后两个要点的文本替换“故意”的假设,我将接受这个答案。 (2认同)