Python dict 文字会按照它的写入顺序进行评估吗?
Will a Python dict literal be evaluated in the order it is written?
假设我在 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)
我知道 my_dict.keys()
的顺序是未定义的,但我想知道的是 初始化 通过这样的文字是否保证发生在特定顺序。 my_dict['key1']
的值是否始终如断言的那样 1.0
?
根据 Python docs regarding evaluation order,这应该具有明确定义的行为:
In the following lines, expressions will be evaluated in the arithmetic order of their suffixes:
…
{expr1: expr2, expr3: expr4}
…
因此,无论 dict
中的项目最终被 迭代 的顺序如何,文字字典表达式的值(和键!)将始终是评估 的顺序与它们在我的 Python 源代码中出现的顺序相同。
字典求值顺序应该和写的一样,但是有一个outstanding bug,其中值在键。 (该错误最终在 Python 3.5 中修复)。
Python evaluates expressions from left to right.
以及错误报告:
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}
def f(i):
print i
return i
{f(1):f(2), f(3):f(4)}
Guido 表示:
I am sticking with my opinion from before: the code should be fixed. It doesn't look like assignment to me.
此错误已在 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}
由于您的代码不需要首先评估密钥,因此您的代码可以保证正常工作;即使在每个对应值之后评估键,键值对仍然按顺序评估。
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
然而,这也说明了为什么这也不是那么容易修复的原因:值和键在每对之后由 STORE_MAP
in this order; changing the order would either require adding a ROT_TWO
操作码期望,或者
STORE_MAP_EX
期望对被反转的操作码;第一个将是性能下降,而第二个将意味着在处理字节码的每一段代码中都需要处理另一个操作码。
假设我在 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)
我知道 my_dict.keys()
的顺序是未定义的,但我想知道的是 初始化 通过这样的文字是否保证发生在特定顺序。 my_dict['key1']
的值是否始终如断言的那样 1.0
?
根据 Python docs regarding evaluation order,这应该具有明确定义的行为:
In the following lines, expressions will be evaluated in the arithmetic order of their suffixes:
… {expr1: expr2, expr3: expr4} …
因此,无论 dict
中的项目最终被 迭代 的顺序如何,文字字典表达式的值(和键!)将始终是评估 的顺序与它们在我的 Python 源代码中出现的顺序相同。
字典求值顺序应该和写的一样,但是有一个outstanding bug,其中值在键。 (该错误最终在 Python 3.5 中修复)。
Python evaluates expressions from left to right.
以及错误报告:
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}
def f(i): print i return i {f(1):f(2), f(3):f(4)}
Guido 表示:
I am sticking with my opinion from before: the code should be fixed. It doesn't look like assignment to me.
此错误已在 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}
由于您的代码不需要首先评估密钥,因此您的代码可以保证正常工作;即使在每个对应值之后评估键,键值对仍然按顺序评估。
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
然而,这也说明了为什么这也不是那么容易修复的原因:值和键在每对之后由 STORE_MAP
in this order; changing the order would either require adding a ROT_TWO
操作码期望,或者
STORE_MAP_EX
期望对被反转的操作码;第一个将是性能下降,而第二个将意味着在处理字节码的每一段代码中都需要处理另一个操作码。