Следующий код содержит разделение в старом стиле.
(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)
Или записанный в другом порядке результат должен оцениваться как
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). Мне это кажется серьезной ошибкой.
Самый полезный комментарий
У меня тоже есть эта проблема, я запускаю futurize 0.17.1 на Python 2.7.16. Этот пример иллюстрирует проблему:
Обратите внимание, что
100/10 * 10
(== 100) преобразуется вold_div(100,10 * 10)
(== 1). Мне это кажется серьезной ошибкой.