[英]Best way to write Python 2 and 3 compatible code using nothing but the standard library
I am trying to make some of my code Python 2 and 3 compatible. 我试图使我的一些代码Python 2和3兼容。
At the moment I am struggling with functions like range
/ xrange
and methods like dict.items
/ dict.iteritems
. 目前,我正在努力使用range
/ xrange
等函数以及像dict.items
/ dict.iteritems
这样的方法。 Ideally I would like my code to be able to use the former in Python 3.x and the latter in Python 2.x. 理想情况下,我希望我的代码能够在Python 3.x中使用前者,在Python 2.x中使用后者。
Using if
/ else
seems to me to be the easiest way to implement this: 使用if
/ else
似乎是我实现这个的最简单方法:
if py >= 3:
for item in array.items()
...
else:
for item in array.iteritems()
However, doing like that results in lots of repeated and ugly code. 但是,这样做会导致大量重复和丑陋的代码。 Is there a better way to do that using only the standard library ? 有没有更好的方法只使用标准库 ? Can I just state somewhere at the beginning of the code to always use range
/ dict.items
if py >= 3
and xrange
/ dict.iteritems
if not? 我可以在代码开头的某个地方dict.items
如果py >= 3
则始终使用range
/ dict.items
,如果不是,则使用xrange
/ dict.iteritems
吗?
Is it possible to do something like this? 可以这样做吗?
if py < 3:
use xrange as range
I have looked around and I know that several libraries, like six o futurize) are used to solve this issue. 我环顾四周,我知道有几个库,比如六个未来化的库,用于解决这个问题。 However I am working on a server that run only python 2.7 and I am not allowed to install any extra libraries on it. 但是我正在使用只运行python 2.7的服务器,我不允许在其上安装任何额外的库。 I have some python3 code I would like to use but I also want to maintain only one version of the code. 我有一些我想使用的python3代码,但我也想只维护一个版本的代码。
import sys
if sys.version_info.major > 2:
xrange = range
But as Wim implies, this is basically rewriting six yourself. 但正如Wim所暗示的那样,这基本上是自己重写六个 。
And as you can see , six
does a lot more that handling range
. 正如你所看到的 , six
处理range
更多。 Just eg look at the _moved_attributes
list in the six source code. 只需查看六个源代码中的_moved_attributes
列表即可。
And while Python comes with "batteries included", its standard library is not and cannot be all-encompassing. 虽然Python附带“包含电池”,但它的标准库不是也不能包罗万象。 Nor is it devoid of flaws. 它也没有缺陷。
Sometimes there are better batteries out there, and it would be a waste not to use them. 有时会有更好的电池,不使用它们是浪费。 Just compare urllib2
with requests
. 只需将urllib2
与requests
进行比较即可。 The latter is much nicer to work with. 后者更适合使用。
The simple, "Don't Make Me Think!" 简单的,“不要让我思考!” solution I use is to start simple scripts with: 我使用的解决方案是启动简单脚本:
#!/usr/bin/env python
# just make sure that Python 3 code runs fine with 2.7+ too ~98% of the time :)
from __future__ import (division, print_function, absolute_import,
unicode_literals)
from builtins import int
try:
from future_builtins import ascii, filter, hex, map, oct, zip
except:
pass
import sys
if sys.version_info.major > 2:
xrange = range
(Extra tip to stop most pep8 linters for unnecessarily yelling at you for this: move last 3 lines inside and at the top of the try
block above) (额外的提示,以阻止大多数pep8短裤为此不必要地对你大喊:移动最后3行内部和上面的try
块顶部)
But the only case I use this is basically "shell scripts that were too large and hairy so I quickly rewrote them to Python and I just want them to run under both Python 2 and 3 with 0 dependencies". 但我使用它的唯一情况基本上是“太大而且毛茸茸的shell脚本,所以我很快将它们重写为Python,我只希望它们在Python 2和3下运行,具有0依赖性”。 Please do NOT use this in real application/library code until you know exactly what are the consequences of all the lines above, and if they are enough for your use case. 请不要在实际应用程序/库代码中使用它,除非您确切知道上述所有行的后果,以及它们是否足以满足您的用例。
Also, the "solution" in this case for .iteritems
is "just don't use it", ignore memory use optimizations and just always use .items
instead - if this matters, it means you're not writing a "0 dependencies simple script" anymore, so just pick Python 3 and code for it (or Python 2 if you need to pretend we're in 2008). 此外,在这种情况下,对于.iteritems
的“解决方案”是“只是不要使用它”,忽略内存使用优化,而只是总是使用.items
- 如果这很重要,那就意味着你没有写出“0依赖简单”脚本“,所以只需选择Python 3和代码(如果你需要假装我们在2008年,则选择Python 2)。
Also, check these resources to get a proper understanding: 另外,请检查这些资源以获得正确的理解:
( NOTE: I'm answering this already answered question mainly because the accepted answers roughly translates to "you are stupid and this is dumb" and I find this very rude for an SO answer: no matter how dumb the question, and how "wrong" to actually answer it, a question deserves a real answer._ ( 注意:我正在回答这个已经回答的问题,主要是因为接受的答案粗略地翻译为“你是愚蠢的,这是愚蠢的”,我发现这个问题非常粗鲁 :无论问题多么愚蠢,以及如何“错误“要真正回答它,一个问题值得一个真正的答案._
I would recommend writing for py2 or py3 in your projects's modules, but not mix them together and not include any sort of 2/3 checks at all. 我建议在项目的模块中编写py2或py3,但不能将它们混合在一起,根本不包括任何类型的2/3检查。 Your program's logic shouldn't have to care about its version of python, except maybe for avoiding functions on builtin objects that conflict. 你的程序的逻辑不应该关心它的python版本,除了可能避免内置对象冲突的函数。
Instead, import * from your own compatiblity layer that fixes the differences between your framework and use shadowing to make it transparent to your actual project's module. 相反,从您自己的兼容层导入*,它修复了框架之间的差异,并使用阴影使其对您的实际项目模块透明。
For instance, in the compatibility module, you can write Roland Smith's substition for range/xrange, and in your other modules you add "from compatibility import *". 例如,在兼容性模块中,您可以编写Roland Smith的range / xrange替换,并在其他模块中添加“from compatibility import *”。 Doing this, every module can use "xrange" and the compatibility layer will manage the 2/3 differences. 这样做,每个模块都可以使用“xrange”,兼容层将管理2/3的差异。
Unfortunately it won't solve existing objects functions such as dict.iteritems; 不幸的是,它不会解决现有的对象函数,如dict.iteritems; typically you would monkey-patch the dict methods, but it is not possible on builtin types (see https://stackoverflow.com/a/192857/1741414 ). 通常你会修补dict方法,但在内置类型上是不可能的(参见https://stackoverflow.com/a/192857/1741414 )。 I can imagine some workarounds: 我可以想象一些解决方法:
for key in my_dict: value = my_dict[key] # rest of code goes here
I guess you are mixing up array
and dict
in this case. 我想你在这种情况下混合array
和dict
。
If you are restricted in using 3-d party libraries for any reason, so why not like this: 如果您出于任何原因限制使用三维派对库,那么为什么不喜欢这样:
def iterate_items(to_iterate):
if py >= 3:
return to_iterate.items()
else:
return to_iterate.iteritems()
And then use it: 然后使用它:
for item in iterate_items(your_dict):
...
import sys
VERSION = float("{}.{}".format(sys.version_info.major, sys.version_info.minor))
And by using this we can write conditional code for desired versions. 通过使用它,我们可以编写所需版本的条件代码。
if VERSION >= 3.5:
from subprocess import run as _run
else:
from subprocess import call as _run
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.