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,但也欢迎涉及更高版本(可用时)的解决方案/建议/解释。
这是设计使然。引用有关分配的官方文档:
...迭代的第一项从左到右分配给加星标目标之前的目标。可迭代对象的最后一项被分配给加星标的目标之后的目标。然后将迭代中剩余项目的列表分配给加星标的目标(该列表可以为空)。
Python 用户很可能想在y之后改变你的,所以list类型是在tuple.
引用我通过此相关问题中的链接找到的PEP 3132的接受部分:
在对 python-3000 列表 [1] 进行了简短讨论后,Guido 接受了当前形式的 PEP。讨论的可能变化是:
只允许带星号的表达式作为 exprlist 中的最后一项。这将稍微简化解包代码,并允许为带星号的表达式分配一个迭代器。这种行为被拒绝了,因为这太令人惊讶了。
尝试为加星标的目标提供与源可迭代对象相同的类型,例如, b in
a, *b = "hello"将被分配字符串"ello"。这可能看起来不错,但不可能与所有可迭代对象保持一致。使加星标的目标成为元组而不是列表。这将与函数的 一致
*args,但会使结果的进一步处理更加困难。
所以y = tuple(y)之后转换是你唯一的选择。