假设我在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吗?
发布于 2015-01-26 18:52:12
字典计算顺序应该与编写的相同,但是有一个突出的缺陷,其中值在键之前进行求值。(这个bug最终用Python3.5修复了)。
引用参考文献的话
Python从左到右计算表达式。
从臭虫报告来看:
运行以下代码将显示
"2 1 4 3",但在参考手册http://docs.python.org/reference/expressions.html#expression-lists中,计算顺序被描述为{expr1: expr2, expr3: expr4}def (I):打印i返回I {f(1):f(2),f(3):f(4)}
Guido说:
我坚持以前的观点:代码应该是固定的。在我看来不像是任务。
这个bug在Python3.5中是固定的,所以在Python3.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}因为您的代码不需要首先计算键,所以保证代码正确工作;键-值对仍然是按顺序计算的,即使键是在每个对应值之后计算的。
发布于 2015-01-26 18:49:31
根据关于计算顺序的Python文档,这应该具有定义良好的行为:
在下面的行中,表达式将按后缀的算术顺序进行计算: …{expr1: expr2,expr3: expr4}…
因此,不管dict中的项的顺序如何,值(和键)最终都会被迭代。文本字典表达式的计算顺序总是与我的Python源代码中显示的顺序相同。
发布于 2015-03-04 23:58:05
Python3.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按这个顺序期望值和键;更改顺序需要在每对之后添加一个ROT_TWO操作码,或者需要在每对后面添加一个STORE_MAP_EX操作码;第一个操作码是性能下降,而第二个操作码意味着在处理字节码的每段代码中都要处理另一个操作码。
https://stackoverflow.com/questions/28156687
复制相似问题