Python-future: Неправильное преобразование деления в old_div

Созданный на 30 янв. 2019  ·  12Комментарии  ·  Источник: PythonCharmers/python-future

Пример кода

Следующий код содержит разделение в старом стиле.

(x / 2 * 3.0)

Ожидаемый результат

Результат выполнения приведенного выше кода с произвольными значениями, присвоенными x, должен быть следующим, где круглые скобки явно показывают порядок операций (x / 2) * 3.0 . Или записанный в другом порядке результат должен оцениваться как x * (3.0 / 2) .

Проблема

Как только мы запускаем futurize в приведенном выше коде, old_div вставляется фикстурой fix_division_safe . Однако, как видно из приведенного ниже сравнения, функция вызывается с неправильным порядком аргументов.

$ 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

Ожидаемая конверсия

Как уже было сказано в разделе «ожидаемый результат», правильное преобразование должно было быть: (old_div(x, 2) * 3.0)

0.18 bug

Самый полезный комментарий

У меня тоже есть эта проблема, я запускаю futurize 0.17.1 на Python 2.7.16. Этот пример иллюстрирует проблему:

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

Обратите внимание, что 100/10 * 10 (== 100) преобразуется в old_div(100,10 * 10) (== 1). Мне это кажется серьезной ошибкой.

Все 12 Комментарий

Или записанный в другом порядке результат должен оцениваться как x * (3.0 / 2) .

Хотя математически это эквивалентно, это не равно на Python 2. Если x - это int , тогда x / 2 в некоторых случаях будет усекаться первым, тогда как (3.0 / 2) будет всегда равняться 1,5 и никогда не усекать.

Хотя, конечно, бага это не меняет.

Я тоже так думал, поэтому я использовал Python 2.7.15, а также Python 3.7.1 для запуска примера и проверки того, что они показывают такое же поведение. Приятно слышать, что мое первое намерение не было полностью ошибочным.

Может это тоже связано с ОС? Я запускаю пример в Windows 7 x64.

Вы можете привести пример, в котором Python 2 оценит выражение по-другому?

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

(Ваша ожидаемая конверсия, конечно, является правильным результатом.)

Совершенно то, что я ожидал. Однако я явно протестировал использование 1 для x и в результате получил 1,5.

Я также забыл упомянуть, что есть другой вывод кода, если вы не используете круглые скобки. В этом случае Futurize вернет правильную конвертацию.

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

Я столкнулся с той же ошибкой и работаю над исправлением в своей ветке .
Кажется, мои изменения решают эту проблему следующим образом:

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

Исходный результат

$ 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

Новый вывод

$ 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

Я собираюсь создать пул-реквест, когда увижу время ..

Вот еще примеры.

Я также забыл упомянуть, что есть другой вывод кода, если вы не используете круглые скобки. В этом случае Futurize вернет правильную конвертацию.

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

Вопреки тому, что вы сказали, я вижу, что 1 / 2 * 3.0 конвертируется в old_div(1, 2 * 3.0) неправильно с использованием текущего кода на главном сервере.

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

Исходный результат

$ 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

Новый вывод

$ 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 создан (https://github.com/PythonCharmers/python-future/pull/441)

Я также заметил, что old_div вставляется, даже когда левый и правый операнды являются плавающими, например

1.0/1024.0

становится

old_div(1.0,1024.0)

Я думаю, что в этом преобразовании нет необходимости, поскольку деление, в котором оба операнда являются числами с плавающей запятой, дает один и тот же результат как в Python 2, так и в Python 3.

@mattgathu Какую версию Futurize и Python вы используете? В Python 3.7.2 и Futurize 0.17.1 (последняя версия в PyPI) 1.0/1024.0 остается неизменным, когда 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.

Вот мои версии:

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

Я обновился до

На самом деле кажется, что v0.17.0 включает улучшение, позволяющее пропускать ненужные преобразования.

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

Исправьте fix_division_safe для поддержки лучшего преобразования сложных выражений и пропустите очевидное деление с плавающей запятой.

У меня тоже есть эта проблема, я запускаю futurize 0.17.1 на Python 2.7.16. Этот пример иллюстрирует проблему:

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

Обратите внимание, что 100/10 * 10 (== 100) преобразуется в old_div(100,10 * 10) (== 1). Мне это кажется серьезной ошибкой.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги