简体   繁体   English

只使用标准库编写Python 2和3兼容代码的最佳方法

[英]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 . 只需将urllib2requests进行比较即可。 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: 我可以想象一些解决方法:

  • Function wrappers (essentially sobolevn's answer) 函数包装器(基本上是sobolevn的答案)
  • Don't use .items() functions at all; 不要使用.items()函数; use simple loops on keys and then access the dictionary with those keys: 在键上使用简单循环,然后使用这些键访问字典:
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. 我想你在这种情况下混合arraydict

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.

相关问题 什么是将python代码写入python文件的最佳方法? - Whats the best way to write python code into a python file? 模仿python即兼容浏览器的最佳方法 - best way to emulate a python ie compatible browser 有没有办法以标准方式编写 websocket 代码? - Is there a way to write websocket code in a standard way? 在 python 中编写引导的最佳方法 - Best way to write bootstrapping in python 使用 Python 鼠兔库合并 RabbitMQ 队列的最佳方法是什么? - What is the best way to merge RabbitMQ queues using Python pika library? 使用 python 标准库网络浏览器的 VS 代码中的 Python 脚本仅在使用调试器扩展时才有效 - Python script in VS code using python standard library webbroswer works only while using debugger extension 如何编写与Python 2和Python 3兼容的异常引发代码? - How to write exception reraising code that's compatible with both Python 2 and Python 3? 在 python 中安装兼容库 - Installing compatible library in python Python:在不使用非标准库的情况下将字符串 output 格式化为表格的灵活方法 - Python: Flexible way to format string output into a table without using a non-standard library 是否存在属性/引用python代码的标准方法? - Is there a standard way to attribute/cite python code?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM