Почему Python не оценивает арифметику с постоянными числами перед компиляцией в байт-код? - PullRequest
43 голосов
/ 22 февраля 2012

В следующем коде почему Python не компилирует f2 в тот же байт-код, что и f1?

Есть ли причина не делать этого?

>>> def f1(x):
    x*100

>>> dis.dis(f1)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (100)
              6 BINARY_MULTIPLY
              7 POP_TOP
              8 LOAD_CONST               0 (None)
             11 RETURN_VALUE
>>> def f2(x):
        x*10*10

>>> dis.dis(f2)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (10)
              6 BINARY_MULTIPLY
              7 LOAD_CONST               1 (10)
             10 BINARY_MULTIPLY
             11 POP_TOP
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE

Ответы [ 2 ]

71 голосов
/ 22 февраля 2012

Это потому, что x может иметь метод __mul__ с побочными эффектами.x * 10 * 10 вызывает __mul__ дважды, в то время как x * 100 вызывает только один раз:

>>> class Foo(object):
...     def __init__ (self):
...             self.val = 5
...     def __mul__ (self, other):
...             print "Called __mul__: %s" % (other)
...             self.val = self.val * other
...             return self
... 
>>> a = Foo()
>>> a * 10 * 10
Called __mul__: 10
Called __mul__: 10
<__main__.Foo object at 0x1017c4990>

Автоматическое сворачивание констант и только один раз вызов __mul__ может изменить поведение.

Вы можетеполучите нужную оптимизацию, переупорядочив операцию так, чтобы константы умножались первыми (или, как упоминалось в комментариях, использовали скобки, чтобы сгруппировать их так, чтобы они просто обрабатывались вместе, независимо от положения), таким образом, выражая ваше желаниескладывание должно произойти:

>>> def f1(x):
...     return 10 * 10 * x
... 
>>> dis.dis(f1)
  2           0 LOAD_CONST               2 (100)
              3 LOAD_FAST                0 (x)
              6 BINARY_MULTIPLY     
              7 RETURN_VALUE 
17 голосов
/ 22 февраля 2012

Python вычисляет выражения от слева направо .Для f2() это означает, что сначала он оценит x*10, а затем умножит результат на 10. Попробуйте:

Попробуйте:

def f2(x):
    10*10*x

Это должно быть оптимизировано.

...