2013-07-23 20 views
26

Spójrz na to:Dlaczego te dwie funkcje są różne?

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

Najwyraźniej kompilator został wstępnie oceniony (2+3)*4, które ma sens.

Teraz, jeśli po prostu zmienić kolejność argumentów o *:

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

Wyrażenie nie jest już w pełni wstępnie ocenione! Jaki jest tego powód? Używam CPython 2.7.3.

+2

Wygląda jak usterka w optymalizatorze wizjera. Możesz sprawdzić moduł do śledzenia błędów i sprawdzić, czy jest to znany problem. – user2357112

+4

Przestań używać starego python 2.x ... Na 3.3 (przynajmniej) działa tak, jak powinien. – JBernardo

+1

@JBernardo 2.x i 3.x są bardzo różne; Nie mogę płynnie przełączać się między nimi. – arshajii

Odpowiedz

9

W pierwszym przypadku niezoptymalizowany kod to LOAD 2 LOAD 3 ADD LOAD 4 MULTIPLY, aw drugim przypadku to LOAD 4 LOAD 2 LOAD 3 ADD MULTIPLY. Układ dopasowujący wzór w fold_binops_on_constants() musi obsłużyć pierwsze ADD ok (zastępując LOAD LOAD ADD z LOAD), a następnie wykonuje to samo, aby zrobić to samo z MULTIPLY. W drugim przypadku, gdy ADD (obecnie drugi argument do MULTIPLY zamiast pierwszego) jest przekształcany w stałą, skaner jest zbyt daleko, aby zobaczyć L L M (gdy "kursor" był na LOAD 4 nie wyglądał jak jeszcze L L M).

+0

A zatem jest to wada kompilatora? – arshajii

+3

@arshajii: Prawdopodobnie mógłbyś naprawić błąd w 'peephole.c', po prostu wykonując kopię po instrukcji. Jednak właściwym rozwiązaniem jest nie polegać na optymalizatorze peephole, a zamiast tego fałdować stałe w 'compile.c', gdzie najpierw emituje binopy. Przejście przez AST może propagować informacje o stałej ekspresji z liści i nie będzie miejsca dla tego rodzaju błędów. –

5

Wygląda na to, że ten problem został załatany w języku Python 3.3, co można zobaczyć pod 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 
Powiązane problemy