2013-07-23 18 views
26

Date un'occhiata a questo:Perché queste due funzioni sono diverse?

>>> def f(): 
...  return (2+3)*4 
... 
>>> dis(f) 
    2   0 LOAD_CONST    5 (20) 
       3 RETURN_VALUE 

Evidentemente, il compilatore ha pre-valutato (2+3)*4, che ha un senso.

Ora, se io semplicemente cambiare l'ordine degli operandi di *:

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

L'espressione non è più completamente pre-valutato! Qual è la ragione di questo? Sto usando CPython 2.7.3.

+2

Mi sembra un difetto nell'ottimizzatore dello spioncino. Puoi controllare il bug tracker e vedere se si tratta di un problema noto. – user2357112

+4

Interrompe l'utilizzo di python 2.x vecchio. Su 3.3 (almeno) funziona come dovrebbe. – JBernardo

+1

@JBernardo 2.xe 3.x sono molto diversi; Non riesco a passare senza problemi tra loro. – arshajii

risposta

9

Nel primo caso il codice non ottimizzato è LOAD 2 LOAD 3 ADD LOAD 4 MULTIPLY e nel secondo caso è LOAD 4 LOAD 2 LOAD 3 ADD MULTIPLY. Lo schema di corrispondenza in fold_binops_on_constants() deve gestire il primo ADD ok (sostituendo LOAD LOAD ADD con LOAD) e quindi continua a fare la stessa cosa su MULTIPLY. Nel secondo caso per il momento in cui il ADD (ora il secondo argomento a MULTIPLY invece del primo) viene trasformato in una costante lo scanner è troppo avanti per vedere L L M (quando il "cursore" era su LOAD 4 non sembrava a L L M ancora).

+0

Quindi questa è una carenza del compilatore, quindi? – arshajii

+3

@arshajii: Probabilmente è possibile correggere l'errore in 'peephole.c' semplicemente eseguendo il backup di un'istruzione dopo una piega. Tuttavia la soluzione giusta è quella di non fare affidamento sull'ottimizzatore spioncino e invece piegare le costanti in 'compile.c' dove sta emettendo i binops in primo luogo. Un passaggio sopra l'AST potrebbe propagare le informazioni sull'espressione costante dalle foglie e non ci sarebbe spazio per questo tipo di bug. –

5

Sembra che questo problema sia stato corretto in Python 3.3, come si può vedere here.

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