很负责任地告诉你,你可以放弃 Python 2.0 版本了,因为 Python 3 简直棒极了。当然,如果你能把项目从 Python 2 转移到 Python 3,那就更好了。尽管 Python 3 大受赞扬,但如何将 Python 2 中大量的应用“迁移到 Python 3 中这个问题一直困扰着技术人员们,这篇文章就为你答疑解惑。
Python 2 即将退出历史舞台
Python 3 已经发布十年了。Python 2 的产品寿命结束时间最初被设定为 2015 年,但是它被延长到了 2020 年 1 月 1 日——原因是 2013 和 2014 这两年间,人们还没做好准备将项目“迁移”到 Python 3 上。Python 3.0 几乎无法使用,Python 3.1 和 3.2 比 Python 2 运行慢。造成这种问题的根源在于许多第三方库仍然使用 Python 2。直到 2012 年,200 个最常用的 Python 包中仅有一半迁移到了 Python 3 上,而到了 2018 年,仍然只有 95% 左右的 Python 包被迁移过来,这还都是些人们最常用的 Python 包,至于那些不太常用或不流行的,就更无人问津了,所以最后寿命结束期限又延长了 5 年。这 5 年中,Python 3 的变化不可同日而语。Python 3(3.6 及以上版本)的最新版本不仅运行速度快而且功能丰富。
为什么仍然有一些 Python 2 项目?
从业务的角度来看,迁移的成本太高了。作为开发人员,在过去的几年里,我们编写的每一行 Python 2 代码都是一笔技术债。但大多数公司不是由开发者运营的。所有的商业决策都是经理制定的,而他们的关注点是那些能为公司带来业务价值的项目。事实上,一种在几个月内就会被淘汰的编程语言,不足以让人为它花费时间重写所有项目。将项目从 python2 迁移到 python3 是很昂贵的,而且这么做也不会给公司带来更多价值。虽然它会为项目做些改进,但却不会为产品添加任何新特性。
就像女人的衣柜永远都少了一件晚礼服一样,总是有一些新特性在等待着技术人员去开发,总有一个紧急的漏洞需要修复。如果你是“敏捷开发”(因为现在人人都是敏捷开发),并且有一堆待办事项,如果迁移到 Python 3 能排到待办事项列表中,那也只能是最后一项。如果你是一家小型初创企业,那么你需要的不是完美的、最新的代码,而是要添加新功能并改善用户体验。
如果你是一家大公司,那么情况就不同了。如果迁移大量遗留下来的 Python 代码(甚至有3500 万行 Python 2 代码)那绝对是一件让人崩溃的事。更糟糕的是,如果这些代码中有一些是已经离职的前员工编写的,几乎没有经过测试,文档也很差,老旧过时。但是这些代码仍然能正常工作,只是没有人知道它是如何工作的,多年来都没人用过它们。在某种程度上,你将不得不重写它,因此这些代码一直“半死不活”地留在 Python2 中。
继续使用 Python 2 的风险
我们来做个假设——时间快进两个月,Python 2 彻底“退休”,所有人都在准备迎接 Python 3,而你只能面对着仍在 Python 2 上运行的生产代码望洋兴叹。并开始思考:“最坏的结果是什么?”
结果就是——你可能被黑。当然了,在 Python 3 或其他任何编程语言上也可能被黑,但在 Python 2 上被黑的风险更大。没有人会再更新 Python 2,更不会有人去修复里面的 bug。这还不是最糟糕的,更糟糕的是用户要考虑正在使用的 Package,因为大多数 Package 已经放弃了其 Python 2 版本,明年一月将会有更多 Package 放弃 Python 2。那么,对 Python 2 的依赖越大,出现安全问题的可能性就越大。
即使软件没有任何安全问题,随着时间的推移,它也会慢慢地开始崩溃。如果每次更新部分系统(更新系统保持安全),就会出现系统与新软件不兼容的问题。也许一些开发人员会从 PyPI 中删除他们的 Packages,那么最终的结果就是花越来越多的时间去填坑以使项目继续运行。
Python 2 还有救吗?
是不是只能眼睁睁看着 Python 2“寿终正寝”无计可施?我只能说,如果可以将项目迁移到 Python 3,那就这么做吧。因为迁移后得到的长期收益将远远超过迁移的成本。但是如果可以迁移,相信很多人早已那么做了,就不会阅读本文了。所以我假设你不想迁移项目而是在寻找其他的解决方案,下面是我列出的 Python 2 项目其他解决方案,从我主观出发,按照解决方案难度排序:
· 什么都不做
你可以掩耳盗铃,假装 Python 3 不存在,忽略 Python 2 即将“寿终正寝”的事实。正如我之前提过的,不更新软件,“执着”地冒着数据泄露的风险继续使用 Python 2,即使一些依赖项可能在某个时间停止工作也无所谓。但是,如果仅在计算机上运行的某种内部脚本上使用 Python 2,而且它没有依赖项,那么,什么都不做就是最好的解决方案。如果你的软件可能明年就会过时,这时就要衡量下利弊再慎重决定到底要不要迁移。
· 冻结应用状态
对于那些你不用担心安全问题的内部工具,冻结应用状态是个不错的解决方案(这里所说的“内部”是指断网状态)。但如果一些依赖项出现漏洞,那就麻烦了。明年依赖 Python 2 的项目就会开始出现问题,就像我上文提到的,人们会从 GitHub 甚至 PyPI 上删除旧项目,你还记得删除一个填充文本的库结果所有构建的代码开始崩溃的乌龙事件吗?那时候所有人都嘲笑了 JavaScript,那就做好准备迎接同样的嘲笑吧,只是,可能都不会有人嘲笑你了,因为你所使用的是Python 的弃用版本。
幸运的是,我们还有 docker 和其他允许你创建 immutable containers 的工具。编写一个使用 Python 2 作为基本映像的 Dockerfile。添加依赖项并将应用设置成一个 docker 镜像。将设置好的 image 推入公共或私人存储库。于是,你就拥有了一个带有办公应用的 immutable container,你可以共享它并按照自己的用途使用它,而不必担心某些依赖项不可用。它解决了内部工具的大多数问题。现在能用就快使用吧,别等到 2020 年应用开始出现各种问题时再使用就为时已晚了。
· 改变 Python 翻译器
当我提及“Python 2 不再使用”时,我的意思是“CPython 2 不再使用”。CPython 是最流行的 Python 翻译器,所以对于很多人来说,Python == CPython。但它不是唯一的翻译器。例如,还有可以替代 CPython 的 PyPy。
那么,为什么不是所有人都使用 PyPy 呢?因为 PyPy 有一些限制。如果你的项目非常依赖 C 扩展,那么 PyPy 可能不适合你。但如果你切换到 PyPy,需要用测试来验证是否所有程序正常运行,如果能够运行,你的应用程序甚至可能比以前运行得更快。不得不说,这是一个很好的“副作用”。
PyPy 不是唯一的选择。Intel 保留了自己的 Python 发行版,称为“Intel®Python 发行版”。这是一个支持 Python 的 2.7 和 3.6 的免费发行版。当我与一位该项目参与者交谈时,他们表示不打算在近期内弃用 2.7 版本。
· 商业 Python 发行版
除上述方案外,还有商业解决方案。其中之一是 Red Hat Enterprise Linux (RHEL)。如果你购买了版本 8,直到 2024 年 6 月 Red Hat 将一直为你提供 Python 2 的支持服务。这就相当于为你在 Python 2 上多买了 4 年的 bug 修复和更新,代价就是从免费和开源的编程语言转换到让人付费使用他们发布的 Python。你也可以在网上找到其他 Python 2 付费版本供应商。
· 构建自己的 CPython 2
如果你不想花钱请任何人来修复 Python 2,你可以自己做。你需要做的是:衍生 CPython 存储库,等待漏洞出现,对它们进行修补,编译自己的 CPython 版本,并在生产服务器上使用它。除非你清楚自己在做什么,否则这真的不是个好主意,因为谁都不希望在自己的服务器上引入漏洞。
项目迁移至 Python 3
如果以上选项都不适合你,那么你可能最终会还是会把项目迁移到 Python3。有两种常见的方法可以做到这一点:跨代码或将 Python 2 代码重写为 Python 3。
· 跨代码
跨行代码的意思是同时使用 Python 2 和 Python 3 的代码。这听起来像是要做更多的工作,因为你需要同时支持两个主要的 Python 版本,但是这样会使转换更容易—不会出现 Python2 转换到 Python3 过于突然的问题。首先在 Python 3 下运行测试(当然,大多数测试都会失败),然后不断重写应用程序的各个部分,直到它能够在 Python 2 和 Python 3 上工作为止。接下来要在生产环境中更改 Python 版本,最后删除 Python 2 代码。此方法最大的好处是你可以在迭代中完成此工作。您可以在迁移系统各个部分的同时不断为代码添加新特性,这种方法也是客户喜闻乐见的。
· 将 Python 2 重写为 Python 3
另一种选择是用 Python3 重写 Python2 的部分代码。这个办法轻松些,因为你不用再考虑 Python 2。典型的办法是将应用程序的 Python2 版本保持在生产环境中,在一个单独的 git 中使用 Python3 版本。然后你要不断地测试新版本,当它准备好时,你就可以放弃 Python 2,使用 Python 3 版本。如果有些程序还没有测试就“滚”回到了 Python 2,那就太让人崩溃了。需特别注意的是,这种方法意味着你需要暂停向应用中添加新特性。
· 重新编写应用
最后也是最困难的解决方案,用 Python 3 或你认为最有效的任何其他编程语言从头重写应用程序。这种解决方案可谓“劳民伤财”,而且只有当 Python 2 版本只是一个 prototype 时才有效。但它可以让你完全重新设计你的项目,或许真的对你有用。
到底要不要迁移到 Python 3?
正如我一开始说的那样,如果可以将项目迁移到 python3,那么赶紧做吧。Python3 不仅比 Python 2 快很多,而且它有更多优秀的新特性,例如 asyncio、type hints、ordered dictionaries、f-strings 和更好的 Unicode 支持。风云已起,开发者还应早作打算。
文末源码获取: