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 的原因之一是因为代码很漂亮,我不会容忍用兼容性技巧让它变得丑陋。

请给我你的意见。

4

6 回答 6

1

Yes, you need to write for Python 2.4 syntax to support all of 2.4 - 2.7 in the same codebase.

Some changes in Python 2.6 and 2.7 aim to make it a bit easier to write compatible code with 3.x, but you have to drop support for 2.5 and below to do that.

于 2009-12-09T14:32:12.077 回答
1

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

首先,如果您想为所有python 版本提供所有功能,那么是的,您可能会坚持使用尽可能小的功能子集——因此为 Python 2.4 编写代码。或者,如果它们是纯 python,您可以从较新的解释器中反向移植功能(上下文管理器或协程都不是这种情况)。

或者您可以将版本支持拆分为功能 - 如果您认为有一个(可选)功能可以从上下文管理器中受益匪浅,您可以在单独的模块中提供它,然后说 2.4 用户没有该功能。

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

于 2009-12-09T14:58:50.690 回答
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 代码的一个很好的例子。

最后,您要做的事情并不容易,因此请为大量工作做好准备!

于 2009-12-09T14:58:10.067 回答
0

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

于 2009-12-09T19:28:53.983 回答
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,因此您将拥有一段代码,它只需要具有第二种语法。两种方式都写真的会更优雅吗?

于 2012-03-23T15:48:09.473 回答
0

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

以一种简单的方式,在简单的情况下,这可以在没有单独模块的情况下完成,例如当新版本的 Python 将以前是外部的包作为标准时,例如(例如)simplejson。我们在一些代码中有类似的东西:

try:
    import simplejson as json
except ImportError:
    import json

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

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

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

我们坚持使用旧版本的遗留代码,随着新版本的出现进行调整以支持它们,但保持对旧版本的支持,有时使用小的适配器层。在某个时候,我们的代码的主要版本出现在计划中,我们考虑是否是时候放弃对旧 Python 的支持了。发生这种情况时,我们会尝试跨越多个版本,例如直接从 2.4 升级到 2.6,然后才开始真正利用新语法和不适应的特性。

于 2009-12-09T14:54:35.130 回答