python 安卓移至



Last year I’ve given a workshop about packaging Python projects. One of the participants was a bioinformatics researcher. She needed advice because she wanted to switch from Python 2 to Python 3, but a library she needed was only available for Python 2. Moving the library to Python 3 was pretty interesting and I’ll share here how I did it — or rather how I would do it if I had the same situation again.

去年,我举办了一个有关打包Python项目的研讨会。 参与者之一是生物信息学研究员。 她需要建议,因为她想从Python 2切换到Python 3,但是她所需要的库仅适用于Python2。将库移至Python 3非常有趣,我将在此分享我的工作方式,或者更确切地说,如果我再次遇到同样的情况,我会这样做。

(Local Setup)

Make sure you can execute Python 2 and Python 3 locally. I like pyenv for that:

确保可以在本地执行Python 2和Python 3。 我喜欢pyenv

$ pyenv install 2.7.18
$ pyenv install 3.8.5
$ pyenv local 3.8.5
$ pip --version

Alternatively, you can use conda to switch between Python 2 and 3.

另外,您可以使用conda在Python 2和3之间切换

(General project setup)

The project should be under version control and you need to make sure that people can move back if they need to. You need to pin direct and transitive dependencies. You should have a reproducible environment, such as a Docker container with a fixed Python version like 2.7.18-slim-buster. Add a git tag for the current version, deploy the latest one to pypi, and support your users in pinning that version.

该项目应受版本控制,并且您需要确保人们可以根据需要移回原位。 您需要固定直接和传递依赖 。 您应该具有可复制的环境 ,例如具有固定Python版本(如2.7.18-slim-busterDocker容器 。 为当前版本添加一个git标签 ,将最新的git标签部署到pypi,并支持您的用户固定该版本。

Make sure that you document the current state of the migration to Python 3. Typically this is done via an issue tracker, e.g. the builtin one of Github or Jira.

确保记录了向Python 3迁移的当前状态。通常,这是通过问题跟踪器完成的,例如,内置的Github或Jira。

First make sure that you can execute the tests, that the test coverage is OK (see unit testing series) and that the general style is OK (see lining todo). Set up a CI / CD pipeline.

首先,请确保您可以执行测试,测试范围可以确定(请参阅单元测试系列 ),常规样式可以确定(请参阅衬砌待办事项)。 建立CI / CD管道

(Print statements)

In Python 2, you could write print statements:

在Python 2中,您可以编写打印语句:

print "hello world"

In Python 3, you have to write print functions:

在Python 3中,您必须编写打印函数:

print("hello world")

Luckily, you can also have print functions in Python 2. And confusingly, it does not behave the same way:

幸运的是,您还可以在Python 2中具有打印功能。而且令人困惑的是,它的行为方式也不相同:

py2>>> print(1, 2, 3)
(1, 2, 3)
py3>>> print(1, 2, 3)
1 2 3

You need to import the backported print function to make the Python 2 function behave like the Python 3 function:

您需要导入向后移植的print函数,以使Python 2函数的行为类似于Python 3函数:

py2>>> from __future__ import print_function
py2>>> print(1, 2, 3)
1 2 3

Note that I didn’t use the print_function — I just imported it.

请注意,我没有使用print_function我只是导入了它。

Applying this small change is tedious, but you can use 2to3 to do it for you:

应用此小的更改很繁琐,但是您可以使用2to3为您完成此操作:

$ pip install 2to3
$ 2to3 --fix=print .

(Keeping Python 2 Compatibility)

You should have a version that works for Python 2 and Python 3 in exactly the same way for a while. For bigger projects with lots of dependencies, it’s a big help if they can move gradually forward.

您应该拥有一个可以在一段时间内以完全相同的方式适用于Python 2和Python 3的版本。 对于具有大量依赖关系的较大项目,如果它们可以逐步前进,将有很大帮助。

Python 3 moved/renamed parts of the standard library. This breaks compatibility with Python 2. However, the workaround is simple:

Python 3移动/重命名了标准库的一部分。 这破坏了与Python 2的兼容性。但是,解决方法很简单:

try:
    from urllib.parse import urlparse, urlencode
    from urllib.request import urlopen
except ImportError:
    from urlparse import urlparse
    from urllib import urlencode
    from urllib2 import urlopen

Even nicer is the compatibility library six:

更好的是兼容性库6:

$ pip install six

six can then be used like this in both, Python 2 and Python 3:

然后可以在Python 2和Python 3中像这样使用six

from six.moves.urllib.parse import urlparse, urlencode
from six.moves.urllib.request import urlopen

When you write code only to keep the support for older versions, make sure you add a string that is easy to find. Something like “support for Python 2”

如果仅编写代码以保留对较早版本的支持,请确保添加易于查找的字符串。 诸如“对Python 2的支持”之类的东西

(Iterators)

Python 2 creates a list when you call range(10) whereas Python 3 creates a range object for the same code. In some rare cases, you actually need the list and thus need to change it to list(range(10)) .

调用range(10)时,Python 2创建一个列表,而Python 3为同一代码创建一个range对象。 在极少数情况下,您实际上需要列表,因此需要将其更改为list(range(10))

(input and raw_input)

Python 2 has input and raw_input , but Python 3 only has input. The raw_input of Python 2 is like the input of Python 3.

Python 2具有inputraw_input ,但是Python 3仅具有input 。 Python 2的raw_input类似于Python 3的输入。

(Division and Rounding)

If you apply / to two integers, Python 2 gives you an integer division. Python 3 gives you a float as a result. You can still do integer division with // which works in both, Python 2 and 3:

如果将/应用于两个整数,Python 2将为您提供整数除法。 结果,Python 3给了您一个浮点数。 您仍然可以使用//进行整数除法,这在Python 2和3中都可以使用:

>>> 1 / 2
# Python 2: 0 vs Python 3: 0.5

The rounding behavior at x.5 also changed:

x.5处的舍入行为也发生了变化:

  • Python 2: if two multiples are equally close, rounding is done away from 0
    Python 2 :如果两个倍数相等接近,则四舍五入要从0开始
  • Python 3: if two multiples are equally close, rounding is done toward the even choice
    Python 3 :如果两个倍数相等,则四舍五入取整为偶数选择
>>> round(2.4)
# Python 2: 2.0 vs Python 3: 2>>> round(2.5)
# Python 2: 3.0 vs Python 3: 2>>> round(2.6)
# Python 2: 3.0 vs Python 3: 3

There are ways to get the same rounding behavior in Python 2 and 3.

有一些方法可以在Python 2和3中获得相同的舍入行为

(Unicode and Strings)

Unicode was a big pain in Python 2 and got a lot simpler in Python 3. Unicode support was only added later to Python 2. In Python 2, there was a difference between a Unicode string and a string. Essentially, a string was a bytes object containing ASCII:

Unicode在Python 2中是一个很大的痛苦,而在Python 3中则变得简单得多。Unicode支持只是后来才添加到Python 2中。在Python 2中,Unicode字符串和字符串之间存在区别。 本质上,字符串是一个包含ASCII的字节对象:

>>> a = u"abc"
>>> type(a)
<type 'unicode'>>>> b = "abc"
>>> type(b)
<type 'str'>>>> c = b"abc"
>>> type(c)
<type 'str'>>>> ord('ö')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: ord() expected a character, but string of length 2 found>>> 'ü'[0]
'\xc3'
>>> 'ü'[1]
'\xbc'

In Python 3, it’s the same:

在Python 3中,它是相同的:

>>> a = u"abc"
>>> type(a)
<class 'str'>>>> b = "abc"
>>> type(b)
<class 'str'>>>> c = b"abc"
>>> type(c)
<class 'bytes'>>>> ord('ö')
246>>> 'ü'[0]
'ü'

I could write a lot about Unicode and string representations, but to keep it brief:

我可以写很多关于Unicode和字符串表示形式的文章,但要简短一些:



(Pure Python and Universal Wheels)

A wheel file is a form of distributing Python code. Python code is considered pure if it does not have C extensions. If pure Python code is compatible with Python 2 and Python 3 and distributed via a wheel file, that file is called universal. It should work on every machine with every Python version.

wheel文件是分发Python代码的一种形式。 如果没有C扩展名,则认为Python代码是代码。 如果纯Python代码与Python 2和Python 3兼容并通过wheel文件分发,则该文件称为Universal 它应在具有每个Python版本的每台计算机上运行。

You should always distribute your code in form of a source distribution and a wheel distribution. If you can, try to create and publish one universal wheel.

您应该始终以源代码分发和Wheel分发的形式分发代码。 如果可以,请尝试创建并发布一个通用轮子。

(Create a version support policy)





Photo by Sebastian Herrmann on Unsplash 塞巴斯蒂安·赫尔曼 ( Sebastian Herrmann)Unsplash拍摄的照片

Library creators need to decide which Python versions they want to support. Newer versions of Python have killer features you want to have and supporting all versions takes a lot of time. Make it transparent which versions you want to support and when you want to drop the support. It’s best to link this to bigger projects, e.g. the last 3 major Python versions.

库创建者需要确定他们要支持的Python版本。 较新版本的Python具有您想要的杀手级功能,支持所有版本需要花费大量时间。 使您要支持的版本以及何时放弃支持变得透明。 最好将其链接到更大的项目,例如最近3个主要的Python版本。

You should also know that the Python release cycle was changed in PEP-602.

您还应该知道PEP-602中的Python发布周期已更改。

NEP-29 is the version support policy of NumPy and hopefully, all of the Scientific Python packages will follow it as well.

NEP-29是NumPy的版本支持策略,希望所有的Scientific Python软件包也将遵循它。

(Remove Python 2 Compatibility)


Photo by

JESHOOTS.COM on Unsplash JESHOOTS.COMUnsplash上的 照片

Supporting Python 2 means you need to add additional code and likely that you cannot use some of the killer features of newer Python versions.

支持Python 2意味着您需要添加其他代码,并且可能无法使用更新的Python版本的某些杀手级功能。

When you remove the support for a Python version, do it in one git commit so that the change is clear. Search for that string:

删除对Python版本的支持后,请在一个git commit中执行此操作,以使更改清晰可见。 搜索该字符串:

$ grep -rnI "support for Python 2"

(Use the new stuff!)

Python 3 has some super cool features you should use when you can. Migrating to Python 3 opens up a whole new world:

Python 3具有一些您应该使用的超酷功能。 迁移至Python 3开辟了一个全新的世界:



pyupgrade can help you to use new-style syntax, such as:

pyupgrade可以帮助您使用新型语法,例如:

dict((a, b) for a, b in y)    # -> {a: b for a, b in y}
'%s %s' % (a, b)              # -> '{} {}'.format(a, b)

It’s not strictly necessary to do this, but it makes your code more modern and easier to read.

并非必须这样做,但这会使您的代码更现代且更易于阅读。

(Forking the project)

I was pretty lucky that the maintainers of propy were welcoming the changes. However, with free software, you are not bound by the maintainers’ support. You can simply create a so-called fork: A copy of the original project which you control.

我很幸运,维护者欢迎这些更改。 但是,使用免费软件,您不受维护人员支持的约束。 您可以简单地创建一个所谓的fork:您控制的原始项目的副本。


Scipy has over 3000 forks. Screenshot of Github by Martin Thoma

Scipy有3000多个叉子。 Martin Thoma的Github截图

Forking happens all the time with free software. It’s also a mode of development, where independent developers make changes in their copy (their fork) and create a merge request (Github calls this a pull request (PR)).

使用免费软件时常发生分叉。 这也是一种开发模式,其中独立开发人员在其副本(其分叉)中进行更改并创建合并请求(Github将其称为拉取请求(PR))。

You can also upload your fork to pypi, but please only do this if you want to maintain that fork and continue the independent development.

您也可以将fork上载到pypi,但是只有在要维护该fork并继续进行独立开发时,才可以这样做。

(Metaclasses)

There are topics like metaclasses and exception scopes which I haven’t covered. If you need that, I recommend this tutorial by Mike Müller:

我没有涉及诸如元类和异常范围之类的主题。 如果需要,我推荐MikeMüller撰写的本教程:


演示地址

Anders Hovmöller also wrote an interesting article about this topic. Check his “surprises in production” section!

AndersHovmöller也写了一篇有趣的文章。 检查他的“生产中的惊喜”部分!


(TL;DR: How do I move from Python 2 to Python 3?)

  1. Get a professional Python 2 setup
  2. Move to a state where your codebase supports Python 2 and Python 3
  3. Let it run for a while, make sure it works
  4. Remove Python 2 support

(Related Resources)


翻译自: https://towardsdatascience.com/how-i-moved-a-library-from-python-2-to-3-60fc2b2a21a1

python 安卓移至