支持不同版本的Python

9
这个问题困扰了我一段时间。 对于我的Python项目,我想支持Python 2.4到3.1的多个版本。我考虑了一下如何实现,最终决定为四个不同版本的Python(2.4、2.5、2.6和3.1)分别创建源代码分支。 但现在我认为这是个错误决定,主要是因为Python的分发问题,我需要做四次分发而不是一次。 那么问题来了,怎么办? 我的项目属于科学计算领域,我感觉还有很多人依赖Python 2.4。 有人建议我只为2.4编写整个项目,但这对我来说是不可接受的。这意味着我不能使用上下文管理器,而这是我不会放弃的东西。 普通的Python项目如何支持2.4?他们避免使用上下文管理器吗? 此外,除了为Python 3.1创建一个单独的分支,还有其他选择吗?我知道有各种各样的黑客技巧可以使相同的代码在2.x和3.x上运行,但我喜欢Python的原因之一是代码美观,我不会容忍使用兼容性黑客使其变丑。 请给我你的意见。
6个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
1

是的,您需要编写Python 2.4语法以支持同一代码库中的所有2.4-2.7版本。

Python 2.6和2.7中的一些更改旨在使编写与3.x兼容的代码变得更加容易,但您必须放弃对2.5及以下版本的支持才能实现这一点。


我明白了。我愿意探索不在同一代码库中完成它的选项。事实上,这就是我现在正在做的事情,在极端情况下,为不同的版本拥有单独的分支。也许我可以更聪明地处理它。 - Ram Rachum

1

你的问题似乎有不同的答案。

首先,如果你想为所有的Python版本提供所有的功能,那么你可能只能使用最小的功能子集,因此编写你的代码时要考虑Python 2.4。或者,如果新版本的解释器是纯Python的(上下文管理器或协程不是这种情况),你可以将其特性回溯到旧版本中。

或者,你可以将版本支持分成特性 - 如果你认为有一个(可选的)特性会从上下文管理器中获得巨大的好处,你可以将其放在一个单独的模块中,并且只告诉2.4用户没有该特性。

为了支持Python 3,请查看2to3助手,如果你正确编写你的代码,你就有很大的机会不需要维护两个独立的代码库。


0

我们有一个相关的问题,一个支持jython和cpython回到2.4版本的大型系统。基本上,您需要将需要以不同方式编写的代码隔离到一组希望很小的模块中,并有条件地进行导入。

# module svn.py
import sys
if sys.platform.startswith('java'):
    from jythonsvn import *
else:
    from nativesvn import *
在你的例子中,你会使用对 sys.version_info 的测试。你可以在一个实用模块中定义一些简单的东西,然后像这样使用:from util import *。
# module util.py
import sys
if sys.exc_info[0] == 2:
    if sys.exc_info[1] == 4:
        from util_py4 import *
    ...

然后在util_py4.py中的一些内容,例如:

def any(seq):                # define workaround functions where possible
    for a in seq:
        if a: return True
    return False
...

虽然这与移植不同(因为您想继续支持),但此链接提供了一些有用的指导http://python3porting.com/preparing.html(其他关于移植python 2.x的文章也是如此)。

您说您无法没有上下文管理器有点令人困惑。 尽管上下文管理器功能强大,使代码更易读且最小化错误风险,但您将无法在2.4版本的代码中使用。

### 2.5 (with appropriate future import) and later
with open('foo','rb')as myfile:
   # do something with myfile

### 2.4 and earlier   
myfile = None
try:
    myfile = open('foo','rb')
    # do something with myfile
finally:
    if myfile: myfile.close()

既然你想支持2.4,那么你的代码体系结构必须具备第二种语法。难道用两种方式编写代码真的更优雅吗?


0
如果版本之间的差异不是很大,您可以尝试将它们隔离到一个单独的包或模块中,在其中编写特定于版本的代码以充当适配层。 在简单情况下,可以在没有单独模块的情况下进行这种微不足道的操作,例如当Python的新版本使以前外部的软件包成为标准时,例如simplejson。我们在某些代码中有类似的东西:
try:
    import simplejson as json
except ImportError:
    import json

对于像您可能拥有的非平凡问题,您不希望这些东西随机散布在代码库中,因此应尽可能将其全部收集到一个地方,并使其成为您的代码的唯一版本特定部分。

对于语法不同的事物,例如您想要使用上下文管理器的评论,这种方法可能效果不佳。当然,您可以将上下文管理器代码放在单独的模块中,但这可能会使您使用它的地方变得更加复杂。在这种情况下,您可以将某些关键功能(我认为上下文管理器可以被某种程度地模拟)回溯到此适配器模块。

绝对不能将代码库分开是您可能做的最糟糕的事情,因此我肯定建议您远离这种做法。至少,不要任意使用较新版本的Python功能,因为尽管将它们放入代码中看起来很好(可能简化了特定逻辑块),但必须通过分叉代码库来复制该逻辑,即使在单个模块上也会抵消这些好处。

我们为了遗留代码坚持使用旧版本,随着新版本的发布进行微调以支持它们,但仍然维护对旧版本的支持,有时候需要使用小的适配器层。在某个时刻,我们的代码计划中出现了一个重大版本更新,我们会考虑是否是时候放弃对旧版 Python 的支持。当这种情况发生时,我们尝试跨越几个版本,例如直接从 2.4 跳到 2.6,然后才真正开始利用新的语法和不可适应的特性。


0

首先,您需要记住Python 2.x与其语法基本相同,向后兼容性很强。除了新功能和添加外,还有其他需要考虑的事情,如DeprecationWarning消息,并不会对程序造成伤害,但是它们可能会让人感到不舒服或混乱。

Python 3.x设计为向后不兼容,并旨在摆脱所有旧版本。 Python 2.6引入了许多也在Python 3.x中的更改,以帮助简化过渡。要了解所有更改,建议阅读Python 2.6中的新功能文档。因此,编写适用于Python 2.6的代码,也可以在Python 3.1上运行,但这并非没有注意事项。

即使在2.x版本之间仍然存在许多次要的语法更改,这将要求您将大量代码包装在try/except块中,因此如果这是您愿意做的事情,那么拥有2.x和3.x分支是完全可能的。我认为您会发现,您将对对象进行许多属性和类型测试以实现所需的功能。

我建议您查看一些支持各种Python版本的主要项目的代码。Twisted Matrix是我首先想到的一个。他们的代码是编写Python代码的绝佳示例。

最终,您要开始的工作并不容易,所以请为自己准备好大量的工作!


你在哪里看到2.4-2.6的不同分支了吗?我看到Windows有不同的二进制下载,但源代码似乎只有一个文件夹。我错过了什么吗? - Ram Rachum
setfrozenset 是在 Python 2.4 中添加的。http://www.python.org/doc/2.4.4/whatsnew/whatsnew24.html - u0b34a0f6ae
@cool-RR - 不,是我错过了什么。我删除了错误的信息。@kaizer.se - 谢谢,我把“sets”模块弃用和内置类型的添加混淆了。 - jathanism

0
你可以尝试使用virtualenv,并使用单个Python版本分发你的应用程序。不过这在你的情况下可能实际可行也可能不可行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,