Python-future: Conversión incorrecta de división a old_div

Creado en 30 ene. 2019  ·  12Comentarios  ·  Fuente: PythonCharmers/python-future

Código de ejemplo

El siguiente código contiene una división de estilo antiguo.

(x / 2 * 3.0)

El resultado esperado

El resultado al ejecutar el código anterior con valores arbitrarios asignados ax debe ser el siguiente, donde los paréntesis muestran explícitamente el orden de las operaciones (x / 2) * 3.0 . O escrito en otro orden, el resultado debe evaluarse como x * (3.0 / 2) .

La cuestión

Una vez que corremos futurize en el código anterior, un old_div se inserta por el fix_division_safe accesorio. Sin embargo, como se puede ver en la diferencia a continuación, la función se llama con un orden incorrecto de argumentos.

$ 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

Conversión esperada

Como ya se indicó en la sección 'resultado esperado', la conversión correcta debería haber sido: (old_div(x, 2) * 3.0)

0.18 bug

Comentario más útil

También tengo este problema, ejecutando futurize 0.17.1 en Python 2.7.16. Este ejemplo ilustra el problema:

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

Tenga en cuenta que 100/10 * 10 (== 100) se convierte en old_div(100,10 * 10) (== 1). Esto me parece un error importante.

Todos 12 comentarios

O escrito en otro orden, el resultado debe evaluarse como x * (3.0 / 2) .

Aunque matemáticamente equivalente, esto no es igual en Python 2. Si x es un int , entonces x / 2 se truncará primero en algunos casos, mientras que (3.0 / 2) hará ser siempre 1,5 y nunca truncar.

Aunque, por supuesto, eso no cambia el error.

También lo pensé, por eso usé Python 2.7.15 y Python 3.7.1 para ejecutar el ejemplo y validar que muestran el mismo comportamiento. Es bueno saber que mi primera intención no fue del todo incorrecta.

¿Quizás también esté conectado al sistema operativo? Estoy ejecutando el ejemplo en Windows 7 x64.

¿Puede dar un ejemplo en qué casos Python 2 evaluaría la expresión de otra manera?

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

(Su conversión esperada es, por supuesto, el resultado correcto).

Totalmente lo que hubiera esperado. Sin embargo, probé explícitamente usando 1 para x y obtuve 1.5 como resultado.

También olvidé mencionar que hay una salida diferente del código si no usa los paréntesis. En este caso, futurize producirá la conversión correcta.

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

Encontré el mismo error y estoy trabajando en la solución en mi rama .
Parece que mis cambios solucionan este problema de la siguiente manera:

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

Salida original

$ 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

Nueva salida

$ 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

Voy a crear una solicitud de extracción cuando vea la hora.

A continuación se muestran más ejemplos.

También olvidé mencionar que hay una salida diferente del código si no usa los paréntesis. En este caso, futurize producirá la conversión correcta.

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

Al contrario de lo que dijiste, veo que 1 / 2 * 3.0 se convierte a old_div(1, 2 * 3.0) incorrectamente usando el código actual en el maestro.

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

Salida original

$ 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

Nueva salida

$ 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

RP creado (https://github.com/PythonCharmers/python-future/pull/441)

También he observado que old_div se inserta incluso cuando los operandos izquierdo y derecho son flotantes, por ejemplo

1.0/1024.0

se convierte en

old_div(1.0,1024.0)

Creo que esta conversión es innecesaria ya que la división donde ambos operandos son flotantes produce el mismo resultado, tanto en Python 2 como en Python 3.

@mattgathu ¿Qué versión de futurize y Python usas? Con Python 3.7.2 y futurize 0.17.1 (lo último en PyPI), 1.0/1024.0 permanece intacto cuando 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.

Aquí están mis versiones:

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

He actualizado a 0.17.0 y parece no tener el problema. Gracias

De hecho, parece que la v0.17.0 incluye una mejora para omitir conversiones innecesarias.

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

Arregle fix_division_safe para admitir una mejor conversión de expresiones complejas y omitir la división flotante obvia.

También tengo este problema, ejecutando futurize 0.17.1 en Python 2.7.16. Este ejemplo ilustra el problema:

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

Tenga en cuenta que 100/10 * 10 (== 100) se convierte en old_div(100,10 * 10) (== 1). Esto me parece un error importante.

¿Fue útil esta página
0 / 5 - 0 calificaciones