why does dead code costs time?
Ian Kelly
ian.g.kelly at gmail.com
Wed Dec 5 12:59:26 EST 2012
On Wed, Dec 5, 2012 at 10:34 AM, Steven D'Aprano
<steve+comp.lang.python at pearwood.info> wrote:
> The difference is almost certain between the LOAD_CONST and the
> LOAD_GLOBAL.
>
> As to *why* there is such a difference, I believe that's a leftover from
> early Python days when None was not a keyword and could be reassigned.
I think this should even be considered a bug, not just a missing
optimization. Consider:
>>> globals()['None'] = 42
>>> def f(x):
... return None
... print(x)
...
>>> f('test')
42
The use of the LOAD_GLOBAL allows None to effectively be reassigned.
It's also worth noting that:
>>> def f(x):
... return
... print(x)
...
>>> dis.dis(f)
2 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
3 4 LOAD_GLOBAL 0 (print)
7 LOAD_FAST 0 (x)
10 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
13 POP_TOP
So if you just write 'return' rather than 'return None', you get the
correct bytecode. Additionally, the use of LOAD_GLOBAL instead of
LOAD_CONST seems to be linked to having unreachable code at the end of
the function. This is fine:
>>> def f(x):
... if x:
... return None
... print(x)
...
>>> dis.dis(f)
2 0 LOAD_FAST 0 (x)
3 POP_JUMP_IF_FALSE 10
3 6 LOAD_CONST 0 (None)
9 RETURN_VALUE
4 >> 10 LOAD_GLOBAL 1 (print)
13 LOAD_FAST 0 (x)
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
19 POP_TOP
20 LOAD_CONST 0 (None)
23 RETURN_VALUE
But this is not. Note here that *both* loads of None become
LOAD_GLOBAL in this case:
>>> def f(x):
... if x:
... return None
... return None
... print(x)
...
>>> dis.dis(f)
2 0 LOAD_FAST 0 (x)
3 POP_JUMP_IF_FALSE 13
3 6 LOAD_GLOBAL 0 (None)
9 RETURN_VALUE
10 JUMP_FORWARD 0 (to 13)
4 >> 13 LOAD_GLOBAL 0 (None)
16 RETURN_VALUE
5 17 LOAD_GLOBAL 1 (print)
20 LOAD_FAST 0 (x)
23 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
26 POP_TOP
More information about the Python-list
mailing list