>我刚刚在看起来像这样的代码上运行了 2to3 (A(:
def idict(n):
return dict(zip(range(n), range(n)))
它生成了这个 (B(:
def idict(n):
return dict(list(zip(list(range(n)), list(range(n)))))
dict
和zip
都可以使用迭代器,那么为什么要进行这种翻译呢?
B似乎也很慢。测试
python -m timeit -s "import B as t" "t.idict(10)"
结果如下:
________________A______B______C___
Python 2.7.13 2.89 3.82 2.29
Python 3.5.1 2.63 4.34 A
即从 2.89 微缩秒到 4.34 (+50%(,默认翻译。
问题。。(i( 我有理由不应该在 Python 3 中使用原始代码吗?(它产生正确的结果,对我来说似乎是合理的(;(ii( 2to3 是正确的工具吗(我们需要在 2 和 3 上运行,同时转换 python 的 ~150KLOC(
更新:我在表中添加了dict(itertools.izip(xrange(n), xrange(n)))
作为算法 C。
py2to3 看不到全局图片。它只是创建一些等效的代码,通过添加list
包装器来替换现在不再创建列表的函数,以确保:
- 可以下标结果
- 可以根据需要多次迭代结果
(它还在print
、...但在这里无关紧要(
因此,它试图使您的代码运行,但性能根本无法保证。
在您的示例中,列表包装器是无用的,因为dict
使用迭代器。
因此,此工具对于使代码快速工作很有用,但不应在不与原始代码进行比较并决定保留/更改内容的情况下使用此工具。
该工具可能可以改进为:
- 在循环中使用迭代器时避免包装
- 当迭代器传递给将可迭代对象作为输入的对象时,避免包装。
在您的情况下
dict(zip(range(n), range(n)))
完全没问题,在 Python 3 中运行得比在 Python 2 中更快,因为它避免了中间列表创建,所以保持这种方式。
相当于 Python 2的 Python 2 会稍微复杂一些:
dict(itertools.izip(xrange(n), xrange(n)))
如果你有很多代码要翻译,我的建议(我去过那里(:
- 使用
python -3
Switch 与 Python 2 解释器一起公开您的代码并获得一些警告,而不是让它在 Python 3 中崩溃(好吧,它应该警告 Python 3.x 不兼容,2to3 无法微不足道地修复,但它错过了很多情况,好吧,总比没有好,例如它找到了臭名昭著的has_key
调用( - 使用
py2to3
并将结果与原始代码进行比较,手动决定在何处应用更改 - 您还可以使用GrepWin等工具使用多重搜索/替换来执行py2to3会执行的操作,只是降低性能的风险:
- 搜索
iteritems
,替换为items
- 搜索
xrange
,替换为range
- 跟踪
dict.has_key
呼叫,unicode
内置 - 我可能会忘记一些...
使用 - 搜索
- Python 3 广泛测试和公开您的代码。 有些东西对工具和
-3
选项是不可见的,例如当您使用二进制模式读取文本文件等时。