Python-future: Falsche Umwandlung der Division in old_div

Erstellt am 30. Jan. 2019  ·  12Kommentare  ·  Quelle: PythonCharmers/python-future

Beispielcode

Der folgende Code enthält eine Division im alten Stil.

(x / 2 * 3.0)

Das erwartete Ergebnis

Das Ergebnis, das den obigen Code mit willkürlichen x zugewiesenen Werten ausführt, sollte das folgende sein, wobei die Klammern explizit die Reihenfolge der Operationen (x / 2) * 3.0 . Oder in einer anderen Reihenfolge geschrieben, sollte das Ergebnis als x * (3.0 / 2) ausgewertet werden.

Das Thema

Sobald wir futurize mit dem obigen Code ausführen, wird ein old_div vom fix_division_safe Fixture eingefügt. Wie man jedoch im Diff unten sehen kann, wird die Funktion mit einer falschen Argumentreihenfolge aufgerufen.

$ futurize --stage2 src/example.py
RefactoringTool: Refactored src/example.py
--- src/example.py      (original)
+++ src/example.py      (refactored)
@@ -1 +1,3 @@
-(x / 2 * 3.0)
+from __future__ import division
+from past.utils import old_div
+(old_div(x, 2 * 3.0))
RefactoringTool: Files that need to be modified:
RefactoringTool: src/example.py

Erwartete Conversion

Wie bereits im Abschnitt 'erwartetes Ergebnis' angegeben, sollte die korrekte Umrechnung lauten: (old_div(x, 2) * 3.0)

0.18 bug

Hilfreichster Kommentar

Ich habe auch dieses Problem, wenn ich futurize 0.17.1 auf Python 2.7.16 ausführe. Dieses Beispiel veranschaulicht das Problem:

$ echo 'x = 100/10 * 10' | futurize --stage2 -

RefactoringTool: Refactored <stdin>
--- <stdin> (original)
+++ <stdin> (refactored)
@@ -1 +1,3 @@
-x = 100/10 * 10
+from __future__ import division
+from past.utils import old_div
+x = old_div(100,10 * 10)
RefactoringTool: Files that need to be modified:
RefactoringTool: <stdin>

Beachten Sie, dass 100/10 * 10 (==100) in old_div(100,10 * 10) (==1) umgewandelt wird. Das scheint mir ein großer Bug zu sein.

Alle 12 Kommentare

Oder in einer anderen Reihenfolge geschrieben, sollte das Ergebnis als x * (3.0 / 2) ausgewertet werden.

Während dies mathematisch äquivalent ist, ist dies bei Python 2 nicht gleich. Wenn x ein int , dann wird x / 2 in einigen Fällen zuerst abgeschnitten, während (3.0 / 2) tut immer 1,5 sein und nie abschneiden.

An dem Fehler ändert das natürlich nichts.

Das dachte ich mir auch, weshalb ich sowohl Python 2.7.15 als auch Python 3.7.1 verwendet habe, um das Beispiel auszuführen und zu überprüfen, ob sie das gleiche Verhalten zeigen. Es ist gut zu hören, dass meine erste Absicht nicht ganz falsch war.

Vielleicht hängt es auch mit dem Betriebssystem zusammen? Ich führe das Beispiel unter Windows 7 x64 aus.

Können Sie ein Beispiel geben, in welchen Fällen Python 2 den Ausdruck anders auswerten würde?

>>> y = range(10)

>>> [x / 2 * 3.0 for x in y]
[0.0, 0.0, 3.0, 3.0, 6.0, 6.0, 9.0, 9.0, 12.0, 12.0]

>>> [x * (3.0 / 2) for x in y]
[0.0, 1.5, 3.0, 4.5, 6.0, 7.5, 9.0, 10.5, 12.0, 13.5]

(Ihre erwartete Konvertierung ist natürlich das richtige Ergebnis.)

Total das, was ich erwartet hätte. Ich habe jedoch explizit mit 1 für x getestet und als Ergebnis 1,5 erhalten.

Ich habe auch vergessen zu erwähnen, dass es eine andere Ausgabe des Codes gibt, wenn Sie die Klammern nicht verwenden. In diesem Fall liefert futurize die korrekte Umrechnung.

1 / 2 * 3.0 - - > old_div(1, 2) * 3.0

Ich bin auf den gleichen Fehler gestoßen und arbeite an der Fehlerbehebung in meinem Zweig .
Es scheint, dass meine Änderungen dieses Problem wie folgt beheben:

$ cat sample.py          
x =  10
(x / 2 * 3.0)

Originalausgabe

$ futurize sample.py 
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored sample.py
--- sample.py   (original)
+++ sample.py   (refactored)
@@ -1,2 +1,4 @@
+from __future__ import division
+from past.utils import old_div
 x =  10
-(x / 2 * 3.0)
+(old_div(x, 2 * 3.0))
RefactoringTool: Files that need to be modified:
RefactoringTool: sample.py

Neue Ausgabe

$ futurize sample.py
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored sample.py
--- sample.py   (original)
+++ sample.py   (refactored)
@@ -1,2 +1,4 @@
+from __future__ import division
+from past.utils import old_div
 x =  10
-(x / 2 * 3.0)
+(old_div(x, 2) * 3.0)
RefactoringTool: Files that need to be modified:
RefactoringTool: sample.py

Ich werde eine Pull-Anfrage erstellen, wenn ich Zeit sehe..

Hier sind weitere Beispiele.

Ich habe auch vergessen zu erwähnen, dass es eine andere Ausgabe des Codes gibt, wenn Sie die Klammern nicht verwenden. In diesem Fall liefert futurize die korrekte Umrechnung.

1 / 2 * 3.0 - - > old_div(1, 2) * 3.0

Im Gegensatz zu dem, was Sie gesagt haben, sehe ich, dass 1 / 2 * 3.0 old_div(1, 2 * 3.0) fälschlicherweise unter Verwendung des aktuellen Codes auf Master in

$ cat sample2.py
1 / 2 * 3.0
x =  10
x / 2
x / 2.0
x / 2 * 3
x / (2 * 3)
x * 2 / 3

Originalausgabe

$ futurize sample2.py
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored sample2.py
--- sample2.py  (original)
+++ sample2.py  (refactored)
@@ -1,7 +1,9 @@
-1 / 2 * 3.0
+from __future__ import division
+from past.utils import old_div
+old_div(1, 2 * 3.0)
 x =  10
-x / 2
+old_div(x, 2)
 x / 2.0
-x / 2 * 3
-x / (2 * 3)
-x * 2 / 3
+old_div(x, 2 * 3)
+old_div(x, (2 * 3))
+old_div(x * 2, 3)
RefactoringTool: Files that need to be modified:
RefactoringTool: sample2.py

Neue Ausgabe

$ futurize sample2.py
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored sample2.py
--- sample2.py  (original)
+++ sample2.py  (refactored)
@@ -1,7 +1,9 @@
-1 / 2 * 3.0
+from __future__ import division
+from past.utils import old_div
+old_div(1, 2) * 3.0
 x =  10
-x / 2
+old_div(x, 2)
 x / 2.0
-x / 2 * 3
-x / (2 * 3)
-x * 2 / 3
+old_div(x, 2) * 3
+old_div(x, (2 * 3))
+old_div(x * 2, 3)
RefactoringTool: Files that need to be modified:
RefactoringTool: sample2.py

PR erstellt (https://github.com/PythonCharmers/python-future/pull/441)

Ich habe auch beobachtet, dass old_div dann eingefügt wird, wenn sowohl der linke als auch der rechte Operand Gleitkommazahlen sind, z

1.0/1024.0

wird

old_div(1.0,1024.0)

Ich denke, diese Konvertierung ist unnötig, da die Division, bei der beide Operanden Floats sind, sowohl in Python 2 als auch in Python 3 das gleiche Ergebnis liefert.

@mattgathu Welche Version von Futurize und Python verwenden Sie? Mit Python 3.7.2 und futurize 0.17.1 (der neuesten Version von PyPI) bleibt 1.0/1024.0 intakt, wenn futurize d.

$ python --version
Python 3.7.2
$ futurize --version
0.17.1

$ cat test.py
1.0 / 1024.0
1   / 1024.0
1.0 / 1024

$ futurize test.py
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: No files need to be modified.

Hier meine Versionen:

$ python -V
Python 2.7.16
$ futurize --version
0.16.0

Ich habe auf 0.17.0 aktualisiert und es scheint das Problem nicht zu haben. Vielen Dank

Tatsächlich scheint v0.17.0 eine Verbesserung zu enthalten, um unnötige Konvertierungen zu überspringen.

https://github.com/PythonCharmers/python-future/releases/tag/v0.17.0

Fix_division_safe korrigiert, um eine bessere Konvertierung komplexer Ausdrücke zu unterstützen und die offensichtliche Gleitkomma-Division zu überspringen.

Ich habe auch dieses Problem, wenn ich futurize 0.17.1 auf Python 2.7.16 ausführe. Dieses Beispiel veranschaulicht das Problem:

$ echo 'x = 100/10 * 10' | futurize --stage2 -

RefactoringTool: Refactored <stdin>
--- <stdin> (original)
+++ <stdin> (refactored)
@@ -1 +1,3 @@
-x = 100/10 * 10
+from __future__ import division
+from past.utils import old_div
+x = old_div(100,10 * 10)
RefactoringTool: Files that need to be modified:
RefactoringTool: <stdin>

Beachten Sie, dass 100/10 * 10 (==100) in old_div(100,10 * 10) (==1) umgewandelt wird. Das scheint mir ein großer Bug zu sein.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen