如何将dict(zip(range(n), range(n)))翻译成Python 3?



>我刚刚在看起来像这样的代码上运行了 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)))))

dictzip都可以使用迭代器,那么为什么要进行这种翻译呢?

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 -3Switch 与 Python 2 解释器一起公开您的代码并获得一些警告,而不是让它在 Python 3 中崩溃(好吧,它应该警告 Python 3.x 不兼容,2to3 无法微不足道地修复,但它错过了很多情况,好吧,总比没有好,例如它找到了臭名昭著的has_key调用(
  • 使用py2to3并将结果原始代码进行比较,手动决定在何处应用更改
  • 您还可以使用GrepWin等工具使用多重搜索/替换来执行py2to3会执行的操作,只是降低性能的风险:
    • 搜索iteritems,替换为items
    • 搜索xrange,替换为range
    • 跟踪dict.has_key呼叫,unicode内置
    • 我可能会忘记一些...
  • 使用
  • Python 3 广泛测试和公开您的代码。 有些东西对工具和-3选项是不可见的,例如当您使用二进制模式读取文本文件等时。