Python-future: 除法到 old_div 的错误转换

创建于 2019-01-30  ·  12评论  ·  资料来源: PythonCharmers/python-future

示例代码

下面的代码包含一个旧样式的划分。

(x / 2 * 3.0)

预期的结果

使用分配给 x 的任意值运行上述代码的结果应如下所示,其中括号明确显示操作(x / 2) * 3.0的顺序。 或者以其他顺序编写,结果应评估为x * (3.0 / 2)

问题

一旦我们在上面的代码上运行futurizeold_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

最有用的评论

我也有这个问题,在 Python 2.7.16 上运行 futurize 0.17.1。 这个例子说明了这个问题:

$ 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 上并不相等。如果xint ,则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]

(您的预期转换当然是正确的结果。)

完全符合我的预期。 但是,我明确地对 x 使用 1 进行了测试,结果得到了 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使用 master 上的当前代码错误地转换为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 中的最新版本),当futurize d 时1.0/1024.0保持不变。

$ 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

我已经升级到0.17.0 ,似乎没有这个问题。 谢谢

事实上,v0.17.0 似乎包含一个增强功能,可以跳过不必要的转换。

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

修复 fix_division_safe 以支持更好的复杂表达式转换,并跳过明显的浮点除法。

我也有这个问题,在 Python 2.7.16 上运行 futurize 0.17.1。 这个例子说明了这个问题:

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