[英]Will a Python dict literal be evaluated in the order it is written?
Let's say that I've got a situation like this in Python:假设我在 Python 中遇到过这样的情况:
_avg = {'total':0.0, 'count':0} # HACK: side-effects stored here
def procedure(n):
_avg['count'] += 1
_avg['total'] += n
return n
def get_average():
return _avg['total'] / _avg['count']
my_dict = {
'key0': procedure(0),
'key2': procedure(2),
'key1': get_average()
}
assert(my_dict['key1'] == 1.0)
I know that the order of my_dict.keys()
is undefined, but what I'm wondering is whether the initialization via a literal like this is guaranteed to happen in a particular order.我知道my_dict.keys()
的顺序是未定义的,但我想知道的是,通过这样的文字进行的初始化是否保证以特定的顺序发生。 Will the value of my_dict['key1']
always be 1.0
as asserted? my_dict['key1']
的值my_dict['key1']
总是如断言的1.0
?
Dictionary evaluation order should be the same as written, but there is a outstanding bug where values are evaluated before the keys .字典求值顺序应该和写的一样,但是有一个突出的错误,值在键之前求值。 (The bug was finally fixed in Python 3.5). (该错误最终在 Python 3.5 中修复)。
Quoting from the reference documentation :引用参考文档:
Python evaluates expressions from left to right. Python 从左到右计算表达式。
and from the bug report:并从错误报告:
Running the following code shows
"2 1 4 3"
, but in reference manual http://docs.python.org/reference/expressions.html#expression-lists the evaluation order described as{expr1: expr2, expr3: expr4}
运行以下代码显示"2 1 4 3"
,但在参考手册http://docs.python.org/reference/expressions.html#expression-lists 中,评估顺序描述为{expr1: expr2, expr3: expr4}
def f(i): print i return i {f(1):f(2), f(3):f(4)}
and Guido stated:圭多说:
I am sticking with my opinion from before: the code should be fixed.我坚持我以前的观点:代码应该被修复。 It doesn't look like assignment to me.对我来说这看起来不像是任务。
This bug is fixed in Python 3.5, so on Python 3.4 and earlier the values are still evaluated before the keys:此错误在 Python 3.5 中已修复,因此在 Python 3.4 及更早版本中,仍会在键之前评估值:
>>> import sys
>>> sys.version_info
sys.version_info(major=3, minor=4, micro=2, releaselevel='final', serial=0)
>>> def f(i):
... print(i)
... return i
...
>>> {f(1):f(2), f(3):f(4)}
2
1
4
3
{1: 2, 3: 4}
Since your code doesn't require the keys to be evaluated first, your code is guaranteed to work correctly;由于您的代码不需要首先评估密钥,因此您的代码可以保证正常工作; key-value pairs are still evaluated in order even if the keys are evaluated after each corresponding value.即使在每个对应的值之后对键进行求值,键值对仍按顺序求值。
According to the Python docs regarding evaluation order , this should have well-defined behavior:根据有关评估顺序的Python 文档,这应该具有明确定义的行为:
In the following lines, expressions will be evaluated in the arithmetic order of their suffixes:在以下几行中,表达式将按照其后缀的算术顺序进行计算:
… {expr1: expr2, expr3: expr4} …
So, regardless of what order the items in a dict
end up being iterated , the values (and keys!) of a literal dictionary expression will always be evaluated in the same order as they appear in my Python source code.因此,无论dict
的项目最终被迭代的顺序如何,文字字典表达式的值(和键!)将始终按照它们在我的 Python 源代码中出现的顺序进行评估。
The current behaviour on Python 3.4.2 can be very clearly seen in the disassembled bytecode: the values are evaluated before keys, not left-to-right.在反汇编的字节码中可以非常清楚地看到 Python 3.4.2 上的当前行为:在键之前评估值,而不是从左到右。
>>> dis.dis(lambda: {f('1'): f('2'), f('3'): f('4')})
1 0 BUILD_MAP 2
3 LOAD_GLOBAL 0 (f)
6 LOAD_CONST 1 ('2')
9 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
12 LOAD_GLOBAL 0 (f)
15 LOAD_CONST 2 ('1')
18 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
21 STORE_MAP
22 LOAD_GLOBAL 0 (f)
25 LOAD_CONST 3 ('4')
28 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
31 LOAD_GLOBAL 0 (f)
34 LOAD_CONST 4 ('3')
37 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
40 STORE_MAP
41 RETURN_VALUE
However this also shows the reason why this is also not so straightforward to fix: the values and keys are expected by STORE_MAP
in this order;然而,这也说明了为什么这也不是那么容易解决的原因: STORE_MAP
按此顺序需要值和键; changing the order would either require adding aROT_TWO
opcode after each pair, or STORE_MAP_EX
opcode which would expect the pairs to be reversed;改变次序要么需要加入ROT_TWO
每一对中,或之后操作码STORE_MAP_EX
操作码,其将所期望的对被逆转; the first one would be a performance drop, whereas the second would mean yet another opcode to handle in every piece of code that deals with bytecode.第一个将是性能下降,而第二个将意味着在处理字节码的每一段代码中处理另一个操作码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.