
这个话题在论坛上已经基本平息,但在现实世界中仍未消亡。开发者在旧的内部系统、存档脚本或尚未现代化的维护项目中仍会碰到Python 2。
问问任何运维或质量保证团队的人——你仍然会在服务器上看到它,或者更糟糕的是,它被埋藏在部署脚本中。这门语言从技术上讲已经“结束”,但它的影响太大,不可能一夜之间消失。
所以,这不再是关于理论或版本争论的问题。而是关于实际应用。如果你以任何严肃的方式使用Python,了解Python 2和Python 3之间的主要区别是有用的,因为你可能需要同时接触两者——即使是现在。
以下是你真正需要知道的要点。没有废话。
基础:语法看起来如何
让我们从每个人都会立即遇到的事情开始:打印文本。
在Python 2中尝试这个:
print"this runs"
现在在Python 3中做同样的:
print("this also runs")
在Python 2中,print只是一个关键字。不需要括号。但在Python 3中,print是一个函数,所以它需要括号,否则会抛出错误。仅这一变化就使得从2到3的迁移变得很烦人,如果你试图移植旧脚本或混合版本。
单独来看,这不是什么大问题。但它几乎出现在每个文件中。
算术:意想不到的结果
除非你仔细观察,否则你不会注意到这一点。尝试除以整数:
Python 2:
x = 9 / 5# 给你 1(整数数学)
Python 3:
x = 9 / 5# 给你 1.8
在2中,除以整数得到的是……整数。在3中,除法给你浮点数,除非你强迫它不这么做。
有一次,我花了一个小时调试一个报告工具中的四舍五入错误,就是因为这个。脚本最初是用Python 2编写的,然后原样传下来。另外,Python 2允许你通过从未来模块导入真正的除法来修复这个问题,但人们很少记得这样做。
如果你在遗留代码中看到奇怪的数字输出,怀疑整数除法。
字符串在奇怪的地方断开
事情在这里变得更加混乱。
在 Python 2 中:
word = "naïve"
实际上,如果不在前面加上 "u",它会被存储为一个字节字符串:
word = u"naïve"
没有 "u",某些字符会根据终端或解释器的不同而断开或表现异常。Python 2 默认使用普通字节,这是许多 UnicodeDecodeErrors 的根源。
在 Python 3 中,默认情况下字符串是 Unicode。正是你期望的那样。如果你想要原始字节,你必须声明:
raw = b"naïve"
这种区分使得 Python 3 中的字符串处理更加可预测。在 API、文件处理或电子邮件内容中尤其重要。
冗长的循环 & 范围
Python 2 有两个选项:
基本规则:对于大循环,使用 xrange(),这样你就不会构建巨大的列表。
Python 3 将它们合并了。range() 的行为像旧的 xrange()。示例:
for i in range(1000000): # 在内存中不会构建一个巨大的列表
pass
更干净。同时,xrange 在 Python 3 中被移除了,所以如果你在代码中看到它,这会立即告诉你你正在使用哪个 Python 版本。
异常风格
你可能不会在意的一件事,直到它破坏了你的脚本:
Python 2:
try:
fail_something()
except ValueError, e:
print e
Python 3:
try:
fail_something()
except ValueError as e:
print(e)
这个变化很小但很重要。一些工具在迁移过程中处理它,一些则不处理。它几乎总是被 linters 或解释器捕获,但不是在你浪费大量时间之前,如果你对那行代码不熟悉的话。
输入差异
人们经常忘记这一点:
Python 2:
input() → 将输入评估为 Python 代码(危险)
Python 3:
所以如果你在运行用户输入代码并且得到奇怪的结果或错误,请检查它是在 2 还是 3 上运行,以及你是否错误地使用了 raw_input。
如果你正在维护一个旧的命令行界面(CLI)应用程序,而它突然开始在你输入数字时抛出NameError,这可能是原因。
字典迭代
在Python 2中有一个字典吗?
这两个是不同的:
my_dict.items() # 构建一个静态列表
my_dict.iteritems() # 返回一个生成器(节省内存)
在Python 3中,.items()返回一个视图,其工作方式类似于生成器。iteritems()已经不存在了。
这个小差异在你处理大型JSON文件或配置时会显现出来。如果你在Python 2中优化速度/内存,然后移植到3,如果你忘记重新审视这一点,可能会得到奇怪的性能波动。
库支持和生态系统
大多数有意义的库不再支持Python 2了。Django、Requests、Numpy、Pandas——所有当前版本都是Python 3。
你有时可以安装旧版本,但那些版本有它们自己的问题:漏洞、不稳定、缺乏特性。
如果你试图在旧项目中启动一个虚拟环境或使用pip安装,而事情崩溃了,这通常是原因。
此外,Python 2在现代工具上的依赖解析更加困难。
官方支持在2020年停止了,但实际上,大多数开源维护者在那之前就已经转移了。
顽固的遗留系统
我偶尔还会遇到一种情况:2010-2014年左右构建的内部工具和服务从未获得迁移预算。
通常你会发现Python 2为它们提供动力,通过cron运行或设置为后端工作器。
开发者多年前就离开了,没有人愿意触碰部署脚本。你将生命迹象修补得足够长,以保持运行,最终才会有人升级堆栈。
如果这就是你——我理解。有时业务方面会延迟重写,即使技术方面已经准备好。
结语
如果你今天从头开始,就直接使用Python 3。
如果您正在维护一些较旧的东西,了解差异会有很大帮助。您可以节省时间,避免尴尬的错误,并在移植旧工具时建立信心。
2和3之间的这些变化大多是合乎逻辑的。但它们并不兼容,所以即使是小事——比如字符串格式化或循环范围——如果您不了解发生了什么,也可能悄无声息地爆炸。
在混合环境中,精通两者不仅仅是个人喜好的问题,更是生存的问题。
无