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