que - ¿Por qué Python no evalúa la aritmética de números constantes antes de compilar en bytecode?
python es interpretado o compilado (2)
Esto se debe a que x
podría tener un método __mul__
con efectos secundarios. x * 10 * 10
llama a __mul__
dos veces, mientras que x * 100
solo lo llama una vez:
>>> 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>
El plegamiento automático de las constantes y solo llamar a __mul__
una vez podría cambiar el comportamiento.
Puede obtener la optimización que desea al reordenar la operación de manera que las constantes se multipliquen primero (o, como se menciona en los comentarios, usar paréntesis para agruparlas de tal manera que simplemente se operen juntas, independientemente de la posición), haciendo así explícito su deseo de que el plegado suceda:
>>> 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
En el siguiente código, ¿por qué Python no compila f2
con el mismo bytecode que f1
?
¿Hay alguna razón para no hacerlo?
>>> 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
Python evalúa expresiones de izquierda a derecha . Para f2()
, esto significa que primero evaluará x*10
y luego multiplicará el resultado por 10. Intente:
Tratar:
def f2(x):
10*10*x
Esto debería optimizarse.