Supporting Python 3(支持python3)——迁移策略

迁移策略

制作一个向后不兼容的软件版本是有很高风险的。 当人们需要重写他们的软件或者为了支持两个语言或框架的版本维护割裂的版本时, the risk is that they never make the transition and stay on the old version forever, or worse, that they switch to another framework.

For that reason Python versions 2.6 and 2.7 include both several forward compatibility features to enable you to write code for both Python 2 and Python 3, as well as support for migrating in the form of 2to3, a program and package that can convert cod from Python 2 to Python 3. There are other techniques and strategies you can use and there are also different ways to use 2to3. Which strategy to use depends very much on what type of software you are converting.

Only supporting Python 3

The easiest case is when you only need to support one version of Python at a time. In these cases you can just convert your code to Python 3 and forget about Python 2. With this strategy you will first use the 2to3 tool to make an automatic conversion of most of the changes and then fix every problem that remains manually in the Python 3 code. You will probably also want to go through all of the converted code and clean it up, as the 2to3 conversions may not always be the most elegant solution for your case.

Separate branches for Python 2 and Python 3

If you need to continue to support Python 2, the simplest case is having a branch in your source tree with the code for Python 2 and another branch for Python 3. You will then have to make every change on the two different branches, which is a bit more work, but feasible if the code doesn’t change that often.

One problem with this strategy is that your distribution becomes complex, because you now have two distributions and you need to make sure that Python 3 users get the Python 3 version and Python 2 users get the Python 2 version of your package. Solutions for this are documented in Distributing packages.

Converting to Python 3 with 2to3

In complex cases you can support both Python 2 and Python 3 by maintaining the source code in a Python 2 version and converting it with 2to3 for Python 3 support. That means you will have to run 2to3 each time you have made a code change so you can test it under Python 3, but on the other hand2to3 deals with many of the differences.

To do this you need a script that performs the 2to3 conversion, because doing all the steps manually quickly becomes really boring. Since you need to do the conversion every time you have changed something so you can run the tests under Python 3, you want to run the conversion only on the files that have been modified as the conversion can be rather slow. That means that the conversion script should compare time stamps on the files to see which ones have been modified and convert only them, which means the script can not be a trivial shell script.

You can of course write these conversion scripts yourself, but you might not need to. If you are using Distutils it has support for running 2to3 as a part of the build process. This also solves the distribution problems, as this way you can distribute only Python 2 code and 2to3 will be run on that code during install when installed on Python 3. That way you don’t have to have separate packages or even two copies of the code in your package.Distributing packages also has information on this.

However, the lazy coders approach here would be to use Distribute, as it includes some extensions to the 2to3-story.

Using Distribute to support the 2to3 conversion

Distribute[1] is a fork of Phillip J. Eby’s popular Setuptools package and provides Python 3 compatibility, as well as extensions simplifying the support of Python 2 and Python 3 from the same source. Basically what Distribute has done is to extend the principles of the Distutils build_py_2to3command and integrated 2to3 into all parts of the packaging story.

These changes will be merged back into Setuptools during 2013, but at the time of writing Setuptools doesn’t support Python 3.

With Distribute you can add a few extra parameters in the setup.py file to have 2to3 run the conversion at build time. This means you only need to have one version of the source in your version control system and you therefore only need to fix bugs once. You also need only one source release, so you only have to release the software once and there is only one package to download and install for both Python 2 and Python 3.

You still need to run your tests under all versions of Python that you want to support, but Distribute includes a test command that will convert your code with2to3 before running the tests. You can easily set up your package to use that. Then testing becomes just running python setup.py test once for every python version you want to support.

The main drawback with this solution is that you can’t use the earliest versions of 2to3, because they are too buggy. In practice it means you need to have Python 3.1 or later installed on the target machine. This is generally not a problem, as most platforms that support Python 3 already use Python 3.1 for that support.

You can find examples of how to set up your module or package to use Distribute for your Python 3 support under Supporting multiple versions of Python with Distribute as well as in the standard Distribute documentation[2].

Python 2 and Python 3 without conversion

In many cases it’s often perfectly feasible to modify the code so that it runs under both Python 2 and Python 3 without needing any conversion, although you have to apply several tricks to avoid the incompatibilities between Python 2 and Python 3.

Python 2.6 and 2.7 have a lot of forward compatibility, making supporting Python 2.6 and Python 3 much easier than supporting Python 2.5 and Python 3. Supporting 2.5 or even older versions means you have to employ more tricks. Python 3.3 also re-introduces the u‘‘ literal for strings, which helps with one of the major difficulties in supoprting Python 3.

Benjamin Petersons excellent six module[3] also helps by wrapping much of the incompatibilities, and since the need to support older Python versions is shrinking, supporting both Python 2 and Python 3 without conversion is becoming the preferred method.

There are also cases where you can’t use Distribute, or don’t want to. You may need to distribute your code in a format that is not installable with Distutils and therefore not Distribute. In those cases you can’t use Distribute’s 2to3support and then using 2to3 is more work and not using 2to3 becomes a more attractive prospect.

Even if you do use 2to3 for your project as a whole, you still may end up with having to write some code so it runs on both Python 2 and Python 3 without conversion. This is useful for bootstrapping scripts and setup scripts or if your code generates cod from strings, for example to create command line scripts. You can of course have two separate strings depending on the Python version, or even run 2to3 on the string using lib2to3. However, in these cases it’s generally easier to make the generated code snippets run on all Python versions without 2to3.

My recommendation for the development workflow if you want to support Python 3 without using 2to3 is to run 2to3 on the code once and then fix it up until it works on Python 3. Only then introduce Python 2 support into the Python 3 code, using six where needed. Add support for Python 2.7 first, and then Python 2.6. Doing it this way can sometimes result in a very quick and painless process.

There is also a tool called python-modernize which will do a2to3-type conversion of your code, but it will keep Python 2 compatibility together with the six library. This can be a good start.

More information on the techniques necessary to do this is in the chapterSupporting Python 2 and 3 without 2to3 conversion.

Using 3to2

The 2to3 tool is flexible enough for you to define what changes should be done by writing “fixers”. Almost any kind of Python code conversion is imaginable here and 3to2[4] is a set of fixers written by Joe Amenta that does the conversion from Python 3 to Python 2. This enables you to write your code for Python 3 and then convert it to Python 2 before release.

However, there is no Distribute support for 3to2 and also Python 2.5 or earlier do not include the required lib2to3 package. Therefore 3to2currently remains only an interesting experiment, although this may change in the future.

Which strategy is for you?

Applications

Unless your code is a reusable package or framework you probably do not need to support older versions of Python, unless some of your customers are stuck on Python 2 while others demand that you support Python 3. In most cases you can just drop Python 2 support completely.

Python modules and packages

If you are developing some sort of module or package that other Python developers use you would probably like to support both Python 2 and Python 3 at the same time. The majority of your users will run Python 2 for some time to come, so you want to give them access to new functionality, but if you don’t support Python 3, the users of Python 3 must find another package to fulfill their need.

If the package is stable from a functional standpoint, it might be perfectly reasonable to have separate branches in your version control system and make bugfixes on both branches separately, but if your package is under active development you probably want to support both Python 2 and Python 3 at the same time from the same code base. If you want to use the official 2to3 conversion method, or if you want to try to get the code running under both Python 2 and Python 3 without a conversion step depends on what your code does and what versions of Python you need to support.

There are cases where you won’t be able to run the same code under Python 2 and Python 3 without a lot of effort because it relies so much on Python internals that the code becomes too different. There are also cases where the code is so straightforward that running 2to3 on it hardly changes it. Most code is somewhere in between and the decision is not always easy. A good idea is to run 2to3 on your code and look at the differences. If 2to3makes a lot of changes in your code, then you may want to use it to convert the code to minimize the amount of workarounds.

If you can support only Python 2.6 and later then supporting Python 3 without2to3 conversion is probably the best option. Especially if you aren’t much affected by the binary/Unicode switch, or if you only need to support Python 3.3 or later.

If you are already releasing your package using Distutils or its descendants Setuptools and Distribute, then using Distribute’s 2to3 support is easy, and that might be the path of least resistance. You can also start that way and change the code bit by bit to something that doesn’t need converting.

Frameworks

The benefit of using frameworks when developing doesn’t only come from the framework itself, but also from the plugins and extensions available to it. It is therefore important to make it easy for all developers using and extending the framework to switch to Python 3, as you otherwise risk being stuck on Python 2 forever.

If your framework is extended by writing Python packages that uses Distutils, Setuptools or Distribute as a packaging system this means the users of your framework are already in a good position, as they can use Distutils or Distribute for the 2to3 conversion to support both new and old versions of the framework.

If extensions are packaged and distributed in some other way than with Distutils you may want to consider making your own set of support scripts to make the transition easier, or stopping support for older Python versions, so that your third-party package developers don’t have to use2to3.

Summary

In general, if you write end-user software, you can just switch to Python 3, starting with a one-time run of 2to3 on your code. If you write a Python package you want to support both Python 2 and Python 3 at the same time, and you can drop Python 2.5 support, try first to support Python 2 and 3 without2to3 conversion.

If you need to support Python 2.5 or older, using 2to3 is often the best option.

Footnotes

[1] http://pypi.python.org/pypi/distribute
[2] http://packages.python.org/distribute/python3.html
[3] http://pypi.python.org/pypi/six
[4] http://pypi.python.org/pypi/3to2

在湖闻樟注:原文http://python3porting.com/strategies.html

时间: 2024-11-08 18:02:34

Supporting Python 3(支持python3)——迁移策略的相关文章

Supporting Python 3(支持python3)——为Python 3做准备

为Python3作准备 在开始添加Python 3的支持前,为了能够尽可能地顺利过度到Python 3,你应该通过修改对2to3来说很难苦的东西来给你的代码做一些准备.即使你现在不打算迁移到Python 3,有一些事你也可以现在就做,这些事在一些情况下它们甚至会加快你的代码在Python 2下的运行. 你可能想要读在I用现代的用句来改善你的代码 上包含许多其他一些你能够用到你的代码中的改进的章节. 在Python 2.7下运行 这个过程的第一步是让你的代码在Python 2.6或者2.7下运行.

Supporting Python 3(支持python3)——使用你自己的固定器扩展2to3

使用你自己的固定器扩展2to3 2to3是围绕一个叫着lib2to3标准库包的封装.它包含一个代码分析器.一个用于设置修改分析树的固定器和一个巨大的固定器集合.包含在lib2to3里的固定器能做大多数可能自动完全的转换.然而在有些情况下你需要写自己的固定器.我首先想要向你保证这些情况是非常罕见的并且你不可能永远需要这一章,你跳过这一章也不会有什么不好的感觉. When fixers are necessary It is strongly recommended that you don't c

Supporting Python 3(支持python3)——关于本书

关于本书 这本书书是源码在GitHub[5]上的开放性的书,所以任何人都可以给本书提供贡献(在湖闻樟译注: 原文提供pdf版,购买价格可以自定,有条件的话建议扶持下).作者和编辑是Lennart Regebro,以及以后贡献者将列在这里. 这本书是在reStructuredText[1],里写的,使用Sphinx[2]和LaTeX[3] 排版 以及使用CreateSpace[4].印刷.各部分的字体:TeX Gyre Schola主体文本, DejaVu Sans Mono 代码 以及Flux

Supporting Python 3(支持python3)——使用现代的风格改善你的代码

使用现代的风格来改善你的代码 一旦你已经添加了Python 3的支持,你将改成使用Python的新的函数来改进的代码.Once you have added Python 3 support you have a chance to use the newer features of Python to improve your code. Many of the things mentioned in this chapter are in fact possible to do even b

Supporting Python 3(支持python3)——2to3

2to3 Although it's perfectly possible to just run your Python 2 code under Python 3 and fix each problem as it turns up, this quickly becomes very tedious. You need to change every print statement to a print() function, and you need to change every e

Supporting Python 3(支持python3)——欢迎来到Python 3

欢迎来到Python 3 On Christmas Day 1999 I sat down to write my first piece of software in Python. My experience seems to be typical for Python users. I was initially surprised that indentation was significant, it felt scary to not define variables and I w

Supporting Python 3(支持python3)——前言

前言 当我在2002年6月加入python-dev邮件列表时,"Python 3000"(在湖闻樟译注:即Python 3)的团队每隔几个月都会描述一个Python 开发团队希望他们实现的建议,但是因为兼容性的原因都没有办法做到.对我们来说为"Python 3000  可能是"做一些事意味着没有发生任何变化. 但是后来我们开始越来越经常地说在Python 3000可能发生的事.最终到了"Python 3000"因为内部程序员的惰性被经常引用成缩写

Supporting Python 3(支持Python 3)——目录

Supporting Python 3(支持Python 3) 关于本书 关于术语 序 欢迎来到Python 3 是时候了吗? 如果我现在不能切换会怎么样? Python 和它的版本 更多资源 迁移策略 仅支持Python 3 Python 2和Python 3的单独分支 使用2to3转换到Python 3 使用Distribute来支持2to3转换 无需转换支持Python 2 和 Python 3 使用3to2 哪种策略适合你? 应用 Python模块和包 框架 结论 Preparing f

Supporting Python 3——不使用2to3转换支持Python 2和Python 3

不使用2to3转换支持Python 2和Python 3 虽然Python 3的官方文档努阴人们写同时支持Python 2和Python 3的代码,但是在一此情况这是合适的.尤其是你不能放弃支持Python 2.5及更早的版本时,因为Python 2.6引进了相当多的向前兼容. It's possible to make the same code run under earlier versions of Python as well, but then you start getting i