随着终止支持 Python 2 的脚步越来越近(至2020年),为了兼容 Python 2 和 Python 3,许多 Python 包的开发者会使用下面的代码:
1 2 3 4 |
if sys.version_info[0] == 2: # Python 2 code else: # Python 3 code |
在某些方面,Python2 和 Python3 是存在差异的。
six 通过提供一层包装,简化了差异,使得代码在 Python 2 和 Python 3 中可以有相同的行为。举一个例子,通常遍历字典的 key
一般这样做:
1 2 |
for item in dictionary.iteritems(): # code here |
在 Python2 中:
1 2 |
for item in dictionary.items(): # code here |
在 Python 3 中,使用 six
:
1 2 3 4 |
import six for item in six.iteritems(dictionary): # code here |
这种方法在 Python 2 和 Python 3 中可以无缝运行。但是,一些比较复杂的情况如本文开篇展示的例子,就需要借助 if
来实现。同样地,six
通过提供 PY2
和 PY3
两个布尔常量来简化操作。
1 2 3 4 |
if six.PY2: # Python 2 code else: # Python 3 code |
这种方法目前为止还不错。
这就引出了本文的主题,我们确实不知道 Python 4 将会是什么样子,但我们可以肯定的是,从 Python 3 向 Python 4 过渡会很流畅,不会像 Python3 一样无法向后兼容,如果是这样的话,我们就可以无缝地使用为 Python 2 和 Python3 开发的工具包了。
但是情况并非完全如此。通过在 Github 上搜寻,匹配到了大约 300,000个结果,使用了下面这种语法:
1 2 3 4 |
if six.PY3: # Python 3 code else: # Python 2 code |
发现问题了吗?在 six
中,PY3
是这样定义的:
1 |
PY3 = sys.version_info[0] == 3 |
所以,一旦 Python 4 开始应用,PY2
和 PY3
的值将会为 False。
对于 Python 2 ,上述的 if
判断中都将执行 else
。
下面再看一个有问题的代码:
1 2 3 4 |
if six.PY2: # Python 2 code elif six.PY3: # Python 3 code |
在这种情况下,Python 4 中将不会执行任何代码!
为了避免出现这个问题,关键在于我们应该避免在上述 if
声明判断时把 Python 3 当做特例,而是将 Python 2 当做特例,Python 3 作为默认条件:
1 2 3 4 |
if six.PY2: # Python 2 code else: # Python 3 code |
这是一个小改动,但会在以后省去很多让人头疼的问题。所以,如果你在开发 Python 包,检查下你的代码以确保兼容 Python 4。
更新:当然,不使用 six
,也能实现相同的逻辑。如果通过 sys.version_info
进行版本比较,确保不要这样用:
1 2 3 4 |
if sys.version_info[0] == 3: # Python 3 code else: # Python 2 code |
检查 Python 2 版本的代码时,要么交换 if
声明中判断的内容,要么确保使用 >=
。