支持不同版本的Python
这个话题已经困扰我一段时间了。
对于我的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 提供单独的分支之外,还有其他选择吗?我知道有各种各样的 hack 可以让相同的代码在 2.x 和 3.x 上运行,但我喜欢 Python 的原因之一是因为代码很漂亮,而且我不会容忍通过兼容性 hack 让它变得丑陋。
请给我你的意见。
This subject has been disturbing me for some time.
For my Python project I wanted to be able to support Python versions 2.4 to 3.1. I thought a bit about how to do this, and eventually decided to have four separate forks of the source code for four different versions of Python: 2.4, 2.5, 2.6 and 3.1.
I have come to view that as a bad decision, mainly because of Python's distribution annoyances, which I now have to do four times instead of one.
The question is, what to do?
My project is in the scientific computing field. I got the impression that there are still many people who depend on Python 2.4.
Someone suggested I just write my entire project for 2.4, but that is unacceptable for me. That will mean I could not use context managers, and that is something I will not give up on.
How do ordinary Python projects support 2.4? Do they avoid using context managers?
Also, is there any choice but having a separate fork for Python 3.1? I know there are all kinds of hacks for making the same code run on 2.x and 3.x, but one of the reasons I like Python is because the code is beautiful, and I will not tolerate making it ugly with compatibility hacks.
Please, give me your opinion.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
是的,您需要编写 Python 2.4 语法以支持同一代码库中的所有 2.4 - 2.7。
Python 2.6 和 2.7 中的一些更改旨在使编写与 3.x 兼容的代码变得更容易,但您必须放弃对 2.5 及更低版本的支持才能做到这一点。
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.
您的问题似乎有不同的答案。
首先,如果您想为所有 Python 版本提供所有 功能,那么是的,您可能会坚持使用尽可能小的功能子集 - 因此为Python 2.4 编写代码。或者,如果较新的解释器是纯 python,则可以向后移植功能(上下文管理器或协程也不是这种情况)。
或者您可以将版本支持拆分为功能 - 如果您认为有一个(可选)功能可以从上下文管理器中受益匪浅,您可以将其放在单独的模块中,然后说 2.4 用户没有那个功能。
为了支持 Python 3,请查看 2to3 帮助程序,如果您正确编写代码,则很有可能不需要维护两个单独的代码库。
There seem be different answers to your problem.
First, if you want to offer all functions for all python versions then yes, you're probably stuck with using the smallest possible functionality subset - hence writing your code for Python 2.4. Or you could backport features from newer interpreters if they're pure python (that's not the case of context managers or coroutines neither).
Or you could split version support into features - if you think there's one (optional) feature which would have great benefit from, let's say, context managers, you can make it available in a separate module and just say that 2.4 users don't have that feature.
In order to support Python 3 take a look at the 2to3 helper, if you write your code properly there's a fair chance you won't need to maintain two separate codebases.
如果版本之间的差异不是很大,您可以尝试将它们隔离到单独的包或模块中,在其中编写特定于版本的代码以充当适配层。
以一种简单的方式,在简单的情况下,这可以在没有单独的模块的情况下完成,例如当Python的新版本使以前是外部的包成为标准时,例如(例如)simplejson。我们在某些代码中有类似的东西:
对于不平凡的东西,例如您可能拥有的东西,您不希望这些东西随机分散在您的代码库中,因此您应该尽可能将它们全部收集在一个地方,并使其成为代码中特定于版本的唯一部分。
对于语法不同的事情,例如您关于想要使用上下文管理器的评论,这不能很好地工作。当然,您可以将上下文管理器代码放在单独的模块中,但这可能会使您使用它的地方变得复杂。在这种情况下,您可能会将某些关键功能(我认为上下文管理器可以很容易地模拟)向后移植到此适配器模块。
绝对拥有单独的代码库是你能做的最糟糕的事情,所以我当然建议远离它。至少,不要随意使用较新版本的 Python 中的功能,因为尽管将它们放在代码中看起来不错(也许简化了特定的逻辑块),但事实上您必须通过分叉来复制该逻辑代码库,即使是在单个模块上,也只会抵消这些好处。
我们坚持使用旧版本的遗留代码,随着新版本的出现进行调整以支持它们,但保持对旧版本的支持,有时使用小型适配器层。在某个时候,我们的代码的主要版本会出现在日程中,我们会考虑是否是时候放弃对旧版 Python 的支持了。当这种情况发生时,我们会尝试跨越多个版本,例如直接从 2.4 升级到 2.6,然后才开始真正利用新语法和不可适应的功能。
If the differences between versions are not extreme, you can try isolating them into a separate package or module in which you write version-specific code to act as an adaptation layer.
In a trivial fashion, this can be done without the separate module in simple cases, such as when a new version of Python makes standard a package that used to be external, such as (for example) simplejson. We have something similar to this in some code:
For non-trivial stuff, such as what you probably have, you wouldn't want such things scattered randomly throughout your code base, so you should collect it all together in one place, when possible, and make that the sole section of your code that is version-specific.
This can't work so well for things where the syntax is different, such as your comment about wanting to use context managers. Sure, you could put the context manager code in a separate module, but that will likely complicate the places where you'd be using it. In such cases, you might backport certain critical features (I think context managers could be simulated somewhat easily) to this adapter module.
Definitely having separate codebases is about the worst thing you could do, so I'd certainly recommend working away from that. At the least, don't arbitrarily use features from newer versions of Python, since although it may look nice to have them in the code (simplifying a particular block of logic perhaps), the fact that you have to duplicate that logic by forking the codebase, even on a single module, is going to more than negate the benefits.
We stick with older versions for legacy code, tweaking as new releases come out to support them but maintaining support for the older ones, sometimes with small adapter layers. At some point, a major release of our code shows up on the schedule, and we consider whether it's time to drop support for an older Python. When that happens, we try to leapfrog several versions, going (for example) from 2.4 to 2.6 directly, and only then start really taking advantage of the new syntax and non-adaptable features.
首先,您需要记住,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 版本的主要项目的代码。 扭曲矩阵是我第一个想到的。他们的代码是如何编写 Python 代码的精彩示例。
最后,你要做的事情并不容易,所以要做好准备做很多工作!
First of call you need to keep in mind that Python 2.x shares mostly the same syntax which is backward compatible, new features & additions aside. There are other things to consider that aren't necessarily errors, such as DeprecationWarning messages that while not detrimental, are ugly and can cause confusion.
Python 3.x is backward-INcompatible by design and intends to leave all of the old cruft behind. Python 2.6 introduced many changes that are also in Python 3.x to help ease the transition. To see all of them I would recommend reading up on the What's New in Python 2.6 document. For this reason, it is very possible to write code for Python 2.6 that will also run in Python 3.1, but that is not without its caveats.
Even still there are many minor syntax changes even between 2.x versions that will require you you wrap a lot of your code in
try
/except
blocks, so if this is what you're willing to do then having a 2.x and 3.x branch is totally possible. I think you'll find that you'll be doing a lot of attribute and type tests on your objects to do what you want to do.I would recommend you check out the code of major projects out there that support various Python versions. Twisted Matrix is the first one that comes to mind. Their code is a wonderful example of how Python code should be written.
In the end, what you're setting out to do will not be easy, so prepare yourself for a lot of work!
您可以尝试 virtualenv 并使用单个 Python 版本分发您的应用程序。不过,这对于您的情况可能实用,也可能不实用。
You could try virtualenv and distribute your application using a single Python version. This may or may not be practical in your case though.
我们有相关的问题,一个支持 jython 和 cpython 到 2.4 的大型系统。基本上,您需要将需要以不同方式编写的代码隔离到一小部分模块中,并有条件地导入内容。
在您的示例中,您可能会针对 sys.version_info 使用测试。您可以在实用程序模块中定义一些简单的内容,例如: from util import *
然后 util_py4.py 中的内容如下:
虽然这是与移植不同的问题(因为您想继续支持),但此链接给出了一些有用的指导http://python3porting.com/preparing.html(以及有关移植 python 2.x)。
不过,您关于没有上下文管理器就无法生存的评论有点令人困惑。
虽然上下文管理器功能强大,可以使代码更具可读性并最大限度地降低错误风险,但您无法将它们包含在 2.4 版本的代码中。
由于您想要支持 2.4,因此您将拥有只需具有第二种语法的代码体。两种方式都写真的会更优雅吗?
We have related problem, a large system that supports both jython and cpython back to 2.4. Basically you need to isolate code that needs to be written differently into a hopefully small set of modules, and have things get imported conditionally.
In your example you would use tests against sys.version_info, presumably. You could define some simple things in a utility module, that you would use like: from util import *
Then things in util_py4.py like:
Although this is a different problem than porting (since you want to continue to support), this link gives some useful guidance http://python3porting.com/preparing.html (as do a variety of other articles about porting python 2.x).
Your comment that you just cannot live without context managers is a little confusing though.
While context managers are powerful and make the code more readable and minimize the risk of errors, you just won't be able to have them in the code of your 2.4 version.
Since you want to support 2.4 you'll have a body of code that just has to have the second syntax. Will it really be more elegant to write it BOTH ways?