Почему эти две функции различны?
Взгляните на это:
>>> def f():
... return (2+3)*4
...
>>> dis(f)
2 0 LOAD_CONST 5 (20)
3 RETURN_VALUE
Очевидно, компилятор предварительно оценил (2+3)*4
, что имеет смысл.
Теперь, если я просто изменил порядок операндов *
:
>>> def f():
... return 4*(2+3)
...
>>> dis(f)
2 0 LOAD_CONST 1 (4)
3 LOAD_CONST 4 (5)
6 BINARY_MULTIPLY
7 RETURN_VALUE
Выражение уже не полностью предварительно оценивается! Что является причиной этого? Я использую CPython 2.7.3.
Ответы
Ответ 1
В первом случае неоптимизированный код LOAD 2 LOAD 3 ADD LOAD 4 MULTIPLY
, а во втором случае он LOAD 4 LOAD 2 LOAD 3 ADD MULTIPLY
. Шаблон сопоставления в fold_binops_on_constants()
должен обрабатывать первый ADD
ok (заменяя LOAD LOAD ADD
на LOAD
), а затем следует сделать то же самое с MULTIPLY
. Во втором случае к тому времени, когда ADD
(теперь второй аргумент MULTIPLY
вместо первого) превращается в константу, сканер слишком далеко впереди, чтобы увидеть L L M
(когда "курсор" был включен LOAD 4
он еще не был похож на L L M
).
Ответ 2
Похоже, эта проблема была исправлена в Python 3.3, как можно видеть здесь.
>>> def f():
... return (2+3)*4
...
>>> dis(f)
2 0 LOAD_CONST 5 (20)
3 RETURN_VALUE
>>> def f():
... return 4*(2+3)
...
>>> dis(f)
2 0 LOAD_CONST 5 (20)
3 RETURN_VALUE