Note:从Python3.8和PEP 572开始,这一点已经改变,首先计算键.
tl;dr Until Python 3.7:尽管Python does首先计算值(表达式的右侧),但在(C)Python中,this does appear to be a bug根据the reference manual和the grammar以及PEP on dict comprehensions进行计算.
虽然这之前是fixed for dictionary displays,在键之前再次判断值,the patch wasn't amended包括dict理解.This requirement was also mentioned by one of the core-devs in a mailing list thread discussing this same subject
根据参考手册,Python判断expressions from left to right和assignments from right to left;口述理解实际上是一个包含表达式的表达式,not an assignment*:
{expr1: expr2 for ...}
其中,根据相应的rule of the grammar
,人们期望expr1: expr2
的判断与它在显示器中的判断类似.因此,两个表达式都应该遵循定义的顺序,expr1
应该在expr2
之前求值(如果expr2
包含自己的表达式,它们也应该从左到右求值)
dict comps上的PEP还指出,以下内容在语义上应是等效的:
dict理解的语义实际上可以在
>>> dict([(i, chr(65+i)) for i in range(4)])
在语义上等同于:
>>> {i : chr(65+i) for i in range(4)}
元组(i, chr(65+i))
按预期从左到右计算.
当然,将其更改为根据表达式规则进行操作会在创建dict
时产生不一致性.字典理解和带有赋值的for循环会导致不同的求值顺序,但这没关系,因为它只是遵循规则.
虽然这不是一个主要问题,但应该修正(判断规则或文档)以消除歧义.
*Internally,这确实会导致对dictionary对象的赋值,但这不应 destruct 表达式应有的行为.用户对表达式的行为有期望,如参考手册所述.
正如其他回答者所指出的那样,由于你在其中一个表达式中执行了一个变异操作,你就丢弃了任何关于先计算什么的信息;像邓肯一样,使用print
个电话,就可以清楚地知道该怎么做.
有助于显示差异的功能:
def printer(val):
print(val, end=' ')
return val
(固定)字典显示:
>>> d = {printer(0): printer(1), printer(2): printer(3)}
0 1 2 3
(奇数)字典理解:
>>> t = (0, 1), (2, 3)
>>> d = {printer(i):printer(j) for i,j in t}
1 0 3 2
是的,这特别适用于C
Python.我不知道其他实现如何判断这个特定 case (尽管它们都应该符合Python参考手册)
挖掘源代码总是很好的(你也可以找到描述行为的隐藏注释),所以让我们看看文件compile.c
的compiler_sync_comprehension_generator
:
case COMP_DICTCOMP:
/* With 'd[k] = v', v is evaluated before k, so we do
the same. */
VISIT(c, expr, val);
VISIT(c, expr, elt);
ADDOP_I(c, MAP_ADD, gen_index + 1);
break;
这似乎是一个足够好的理由,如果这样判断的话,应该被归类为文档错误.
在我做的一个快速测试中,切换这些语句(首先访问VISIT(c, expr, elt);
个语句),同时也切换相应的order in MAP_ADD
个语句(用于dict comps):
TARGET(MAP_ADD) {
PyObject *value = TOP(); # was key
PyObject *key = SECOND(); # was value
PyObject *map;
int err;
基于文档的判断结果,在值之前判断键.(不是异步版本,这是另一个switch .)
我会对这个问题发表 comments ,并在有人回复我时更新罢工>
在追踪器上创建了Issue 29652 -- Fix evaluation order of keys/values in dict comprehensions个.将在取得进展时更新问题.