支持不同版本的Python

时间:2009-12-09 14:11:11

标签: python python-3.x compatibility multiple-versions

这个话题一直困扰着我。

对于my Python project,我希望能够支持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 个答案:

答案 0 :(得分:1)

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

Python 2.6和2.7中的一些变化旨在使用3.x编写兼容代码变得容易一些,但你必须放弃对2.5及以下版本的支持才能做到这一点。

答案 1 :(得分:1)

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

首先,如果你想为所有 python版本提供所有函数,那么是的,你可能会坚持使用尽可能小的功能子集 - 因此编写你的代码对于Python 2.4。或者你可以从新的解释器中移植特征,如果它们是纯python(那不是上下文管理器或协同程序的情况)。

或者您可以将版本支持拆分为功能 - 如果您认为有一个(可选)功能可以从上下文管理器中获得很大好处,您可以在单独的模块中使用它,并且只说2.4用户不要没有那个功能。

为了支持Python 3,请查看2to3帮助程序,如果正确编写代码,则很可能不需要维护两个单独的代码库。

答案 2 :(得分:0)

如果版本之间的差异不是极端的,您可以尝试将它们隔离到一个单独的包或模块中,在该包或模块中编写特定于版本的代码以充当适配层。

在简单的情况下,这可以在没有单独模块的情况下完成,例如当新版本的Python将标准包装为曾经是外部的包时,例如(例如)simplejson。我们在某些代码中有类似的内容:

try:
    import simplejson as json
except ImportError:
    import json

对于非平凡的东西,比如你可能拥有的东西,你不会希望这些东西在你的代码库中随机分散,所以你应该在一个地方尽可能地收集它们,并尽可能地将它们作为唯一的部分您的代码是特定于版本的。

对于语法不同的事情,例如关于想要使用上下文管理器的注释,这不能很好地工作。当然,您可以将上下文管理器代码放在一个单独的模块中,但这可能会使您使用它的位置变得复杂。在这种情况下,您可能会向某个适配器模块反向移植某些关键功能(我认为可以轻松地模拟上下文管理器)。

绝对拥有单独的代码库是关于你能做的最糟糕的事情,所以我当然建议你不要这样做。至少,不要随意使用较新版本的Python中的功能,因为尽管将它们放在代码中可能看起来很不错(可能简化了特定的逻辑块),但是必须通过分叉来复制该逻辑。代码库,即使在单个模块上,也不仅仅是否定其优势。

我们坚持使用旧版本的遗留代码,调整新版本以支持它们,但保持对旧版本的支持,有时使用小适配器层。在某些时候,我们的代码的主要版本出现在日程安排上,我们考虑是否是时候放弃对旧Python的支持了。当发生这种情况时,我们会尝试跳过几个版本,直接从2.4到2.6,然后才开始真正利用新语法和不适应性功能。

答案 3 :(得分:0)

首先要记住,你需要记住,Python 2.x的语法大致相同,后向兼容,新功能和除了附加。还有其他需要考虑的因素不一定是错误,例如DeprecationWarning消息,虽然没有损害,但是很丑陋并且可能引起混淆。

Python 3.x在设计上是向后兼容的,并打算抛弃所有旧的背后。 Python 2.6引入了许多也在Python 3.x中的更改,以帮助简化转换。要查看所有这些内容,我建议您阅读What's New in Python 2.6文档。出于这个原因,很有可能为Python 2.6编写也将在Python 3.1中运行的代码,但这并非没有警告。

即使在2.x版本之间仍存在许多次要的语法更改,这些版本会要求您在try / except块中包含大量代码,所以如果这就是您所要求的愿意做一个2.x和3.x分支是完全可能的。我想你会发现你会在你的对象上做很多属性和类型测试来做你想做的事情。

我建议你查看那些支持各种Python版本的主要项目的代码。 Twisted Matrix是第一个浮现在脑海中的人。他们的代码是如何编写Python代码的一个很好的例子。

最后,你要做的事情并不容易,所以要做好大量工作的准备!

答案 4 :(得分:0)

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

答案 5 :(得分: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,你将拥有一组必须具有第二种语法的代码。用两种方式写它真的会更优雅吗?