Pau*_*zer 70 python tuples list splat python-3.x
考虑例如
squares = *map((2).__rpow__, range(5)),
squares
# (0, 1, 4, 9, 16)
*squares, = map((2).__rpow__, range(5))
squares
# [0, 1, 4, 9, 16]
Run Code Online (Sandbox Code Playgroud)
因此,在所有其他条件相等的情况下,当我们在lhs上进行排序时,会得到一个列表,而当我们在rhss上进行布局时,会得到一个元组。
为什么?
这是设计使然吗,如果是的话,其原理是什么?否则,是否有任何技术原因?还是只是这样,没有特殊原因?
use*_*ica 46
您在RHS上获得元组的事实与splat无关。splat只会解压缩您的map迭代器。你解压到由你使用的元组语法的事实决定:
*whatever,
Run Code Online (Sandbox Code Playgroud)
而不是列表语法:
[*whatever]
Run Code Online (Sandbox Code Playgroud)
或设置语法:
{*whatever}
Run Code Online (Sandbox Code Playgroud)
您可能已经获得一个列表或一组。您刚刚告诉Python创建一个元组。
在LHS上,分散的分配目标始终会产生一个列表。是否使用“元组样式”都没关系
*target, = whatever
Run Code Online (Sandbox Code Playgroud)
或“列表样式”
[*target] = whatever
Run Code Online (Sandbox Code Playgroud)
目标列表的语法。该语法看起来很像创建列表或元组的语法,但是目标列表语法是完全不同的事情。
PEP 3132中引入了您在左侧使用的语法,以支持诸如以下的用例
first, *rest = iterable
Run Code Online (Sandbox Code Playgroud)
在拆箱任务中,将iterable的元素按位置分配给未加星标的目标,如果有加星标的目标,则将所有多余内容填充到列表中并分配给该目标。选择一个列表而不是一个元组可以使进一步处理变得容易。由于您的示例中只有加星标的目标,因此所有项目都位于分配给该目标的“附加”列表中。
Dev*_*ngh 30
这是在PEP-0448缺点中指定的
虽然
*elements, = iterable使元素成为列表,但elements = *iterable,使元素成为元组。原因可能会使不熟悉该结构的人感到困惑。
同样按照:PEP-3132规范
该PEP提议对可迭代的解包语法进行更改,从而允许指定“全包”名称,该名称将被分配所有未分配给“常规”名称的项目的列表。
这里也提到:Python-3 exprlists
除非列表或集合显示的一部分,否则包含至少一个逗号的表达式列表会产生一个元组。
仅需使用尾部逗号才能创建单个元组(也称为单例);在所有其他情况下,它都是可选的。没有尾部逗号的单个表达式不会创建元组,而是会产生该表达式的值。(要创建一个空的元组,请使用一对空的括号:()。)
这也可以在这里的一个简单示例中看到,其中列表中的元素
In [27]: *elements, = range(6)
In [28]: elements
Out[28]: [0, 1, 2, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)
在这里,元素是一个元组
In [13]: elements = *range(6),
In [14]: elements
Out[14]: (0, 1, 2, 3, 4, 5)
Run Code Online (Sandbox Code Playgroud)
从评论和其他答案中我可以理解的是:
Thi*_*lle 18
验收
在对python-3000列表[1]进行简短讨论之后,PEP被Guido以其当前形式接受。讨论的可能更改包括:
[...]
将加星标的目标设为元组而不是列表。这与函数的* args一致,但使结果的进一步处理变得更加困难。
[1] https://mail.python.org/pipermail/python-3000/2007-May/007198.html
因此,拥有可变列表而不是不可变元组的优势似乎是原因。
hir*_*ist 13
并不是一个完整的答案,但是拆卸可以提供一些线索:
from dis import dis
def a():
squares = (*map((2).__rpow__, range(5)),)
# print(squares)
print(dis(a))
Run Code Online (Sandbox Code Playgroud)
分解为
5 0 LOAD_GLOBAL 0 (map)
2 LOAD_CONST 1 (2)
4 LOAD_ATTR 1 (__rpow__)
6 LOAD_GLOBAL 2 (range)
8 LOAD_CONST 2 (5)
10 CALL_FUNCTION 1
12 CALL_FUNCTION 2
14 BUILD_TUPLE_UNPACK 1
16 STORE_FAST 0 (squares)
18 LOAD_CONST 0 (None)
20 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
而
def b():
*squares, = map((2).__rpow__, range(5))
print(dis(b))
Run Code Online (Sandbox Code Playgroud)
结果是
11 0 LOAD_GLOBAL 0 (map)
2 LOAD_CONST 1 (2)
4 LOAD_ATTR 1 (__rpow__)
6 LOAD_GLOBAL 2 (range)
8 LOAD_CONST 2 (5)
10 CALL_FUNCTION 1
12 CALL_FUNCTION 2
14 UNPACK_EX 0
16 STORE_FAST 0 (squares)
18 LOAD_CONST 0 (None)
20 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
关于UNPACK_EX状态的文档:
UNPACK_EX(个)
实现带有加星标目标的分配:将TOS中的可迭代项解压缩为单个值,其中值的总数可以小于可迭代项中的项数:新值之一将是所有剩余项的列表。
计数的低字节是列表值之前的值数,计数的高字节是列表值之后的值数。结果值从右到左放入堆栈。
(强调我的)。而BUILD_TUPLE_UNPACK返回tuple:
BUILD_TUPLE_UNPACK(计数)
Pops计算堆栈中的可迭代项,将它们合并到一个元组中,然后推送结果。在元组显示(* x,* y,* z)中实现可迭代的拆包。
我们可以像平常在函数调用中那样工作。它扩展了附加的可迭代对象的内容。因此,该语句:
Run Code Online (Sandbox Code Playgroud)elements = *iterable可以看作:
Run Code Online (Sandbox Code Playgroud)elements = 1, 2, 3, 4,这是元组初始化的另一种方式。
现在,对于LHS,是的,LHS使用清单是有技术原因的,如围绕初始PEP 3132的讨论中所述,用于扩展拆包
可以从PEP上的对话中收集原因(末尾添加)。
从本质上讲,它可以归结为几个关键因素:
摘要:多种因素的综合作用导致决定允许在LHS上列出清单,并且相互之间也得出了理由。
禁止不一致类型的相关摘录:
对于建议的语义,Python的一个重要用例是当您有一个可变长度记录时,其中的前几项很有趣,而其余的则不太有趣,但并非不重要。(如果您想把其余的东西扔掉,只需编写a,b,c = x [:3]而不是a,b,c,* d = x。) d的类型由操作固定,因此您可以依靠它的行为。
Python 2中filter()的设计中存在一个错误(通过将其转换为迭代器BTW将在3.0中修复):如果输入是元组,则输出也是元组,但是如果输入是列表或其他任何东西,输出是一个列表。那是一个完全疯狂的签名,因为这意味着您不能指望结果是列表,也不能指望它是元组- 如果您需要将其作为一个或另一个,则必须将其转换为一个,浪费时间和空间。请不要重复此设计错误。 -圭多
我还尝试过重新创建与上面的摘要有关的部分引用的对话。源 重点矿。
1。
在参数列表中,* args耗尽迭代器,将其转换为元组。我认为,如果元组拆包中的* args没有做同样的事情,那将令人困惑。
这就提出了一个问题,为什么补丁会生成列表而不是元组。这背后的原因是什么?
史蒂夫
2。
IMO,您可能想进一步处理生成的序列,包括对其进行修改。
格奥尔格
3。
好吧,如果这就是您的目标,那么我希望让拆包生成列表而不是列表,而与您开始使用的类型相同,例如,如果我以字符串开头,那么我可能想继续使用它会更有用字符串::- 删除其他文本
4。
在处理迭代器时,您并不事先知道其长度, 因此获取元组的唯一方法是首先生成一个列表,然后从中创建一个元组。 格雷格
5。
是的 这就是建议* args 仅出现在元组解包末尾的原因之一。
史蒂夫
几个convos跳过
6。
我不认为返回给定的类型是应该尝试的目标,因为它只能对固定的一组已知类型起作用。给定任意序列类型,就无法知道如何使用指定的内容为其创建新实例。
-格雷格
跳过常规
7。
我建议:
- 清单返回清单
- 元组返回元组
- XYZ容器返回XYZ容器
- 非容器可迭代对象返回迭代器。
您如何建议区分后两种情况? IMO 尝试对其进行切片并捕获异常是不可接受的,因为它很容易掩盖错误。
-格雷格
8。
但是我希望它没什么用。它也不支持“ a,* b,c =”。在实现POV中,如果RHS上有未知对象,则必须先对其进行切片,然后再尝试对其进行迭代;例如,如果对象恰好是defaultdict,则可能会引起问题 -由于x [3:]被实现为x [slice(None,3,None)],defaultdict将为您提供其默认值。我宁愿通过迭代对象直到用尽它来定义此对象,可以针对某些已知类型(例如列表和元组)对其进行优化。
--吉多(Guido van Rossum)
| 归档时间: |
|
| 查看次数: |
2065 次 |
| 最近记录: |