Let\'s say that I\'ve got a situation like this in Python:
_avg = {\'total\':0.0, \'count\':0} # HACK: side-effects stored here
def procedure(n):
_avg[
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).
Quoting from the reference documentation:
Python evaluates expressions from left to right.
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}
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:
>>> 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:
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.
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.
>>> 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; changing the order would either require adding a ROT_TWO opcode after each pair, or
STORE_MAP_EX
opcode which would expect the pairs to be reversed; 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.