2012-02-22 10 views
42

Nel codice seguente, perché Python non compila f2 allo stesso bytecode come f1?Perché Python non valuta l'aritmetica numerica costante prima di compilarla in bytecode?

C'è un motivo per non farlo?

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

risposta

70

Questo perché x potrebbe avere un metodo __mul__ con effetti collaterali. x * 10 * 10 chiamate __mul__ due volte, mentre x * 100 chiama solo una volta:

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

piegare automaticamente le costanti e solo chiamando __mul__ volta potrebbe cambiare il comportamento.

È possibile ottenere l'ottimizzazione desiderata riordinando l'operazione in modo tale che le costanti vengano moltiplicate per prime (o, come menzionato nei commenti, utilizzando le parentesi per raggrupparle in modo tale che vengano semplicemente utilizzate insieme, indipendentemente dalla posizione), rendendo così esplicito il vostro desiderio per la piegatura avvenga:

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

noti che anche è nulla viene passato al metodo, il risultato di 'dis' è sempre lo stesso cioè se il contenuto del metodo sono:' x = 9; y = x * 10 * 10; ', il risultato è sempre lo stesso vale. caricamento const due volte. Sembra che Python non esegua l'ottimizzazione dell'intero metodo? –

+5

@ SanjayT.Sharma: il compilatore non può ancora sapere cosa sia 'x', quindi deve essere sicuro. L'introspezione versatile di Python e le funzionalità di modifica dinamica del runtime consentono di modificare il tipo di 'x' all'interno della funzione locale. –

+6

'x * (10 * 10)' dovrebbe funzionare anche, ed è un po 'più esplicito. – WolframH

17

Python valuta le espressioni da left to right. Per f2(), questo significa che sarà dapprima valutare x*10 e quindi moltiplicare il risultato per 10. Prova:

Prova:

def f2(x): 
    10*10*x 

Questo dovrebbe essere ottimizzata.

+0

Questo ha funzionato per me in cpython 2.7.2. – jcollado

+1

Fantastico! confermato anche su cpython 2.6.6 – Jonathan

Problemi correlati