2012-02-22 7 views
42

En el siguiente código, ¿por qué Python compila f2 en el mismo bytecode que f1?¿Por qué Python no evalúa la aritmética de números constantes antes de compilar en bytecode?

¿Hay algún motivo 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 

Respuesta

70

Esto es porque x podría tener un método __mul__ con efectos secundarios. x * 10 * 10 llama __mul__ dos veces, mientras que x * 100 só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> 

plegables automáticamente las constantes y sólo llamando __mul__ vez podría cambiar el comportamiento.

Puede obtener la optimización que desee reordenando la operación de modo que las constantes se multipliquen primero (o, como se menciona en los comentarios, utilizando paréntesis para agruparlas de manera que se operen juntas, independientemente de su posición), así haciendo explícita su deseo para el plegado a suceder:

>>> 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 
+0

Tenga en cuenta que incluso si no se pasa nada al método, el resultado de 'dis' sigue siendo el mismo, es decir, si el contenido del método es:' x = 9; y = x * 10 * 10; ', el resultado sigue siendo el mismo. cargando const dos veces. Parece que Python no hace la optimización de todo el método? –

+5

@ SanjayT.Sharma: el compilador todavía no puede saber realmente qué es 'x', por lo tanto, tiene que ir a lo seguro. Las versátiles funciones de introspección y modificación dinámica del tiempo de ejecución de Python hacen posible cambiar el tipo de 'x' dentro de los locales de la función. –

+6

'x * (10 * 10)' debería funcionar también, y es un poco más explícito. – WolframH

17

Python evalúa las expresiones de left to right. Para f2(), esto significa que en primer lugar evaluar x*10 y luego multiplicar el resultado por 10. Probar:

Probar:

def f2(x): 
    10*10*x 

Esto debe ser optimizado.

+0

Esto funcionó para mí en cpython 2.7.2. – jcollado

+1

¡Genial! también confirmado en cpython 2.6.6 – Jonathan

Cuestiones relacionadas