从这篇开始我会不定期写一些在实际工作中把项目代码从Python2.7迁移到最新的Python 3.7的经验。
这篇先介绍pyupgrade - 一个修改代码中Python 2语法到最新版本写法的工具,同时它还可以作为pre-commit钩子,可以在代码提交或者push时拒绝引入旧的用法。
为什么需要这么一个工具呢?3个理由:
-
替换代码中旧版本Python的用法。例如
'%s %s'%(a,b)
这种百分号的字符串格式化写法 -
替换成Python 3的新语法。例如在Python 3中
super
不再需要传递self、字符串格式化在Python 3.6及以后可以直接用f-strings -
迁移后不再需要支持Python2,所以应该去掉six模块的相关使用,直接用Python3的代码写才是正途。
我日常维护的项目中Python代码都在几千到上百万行级别,可以设想一下,如果人工来做代码替换将是一个极为浩大的工程。
在现有的Python世界,过去只有lib2to3模块和其衍生品(之后我会专门讲),但是效果有限,pyupgrade是一个很好的补充,我们来了解一下它都实现了那些功能
集合
左面是替换前的代码,后面井号后的注释部分是替换后的效果。set相关的部分算是统一用法,并不是左面的写法在Python3已经不可用。
字典解析
同上,属于统一用法
Python2.7+ Format说明符
从Python2.7开始,不再强制指定索引
使用str.format替代printf风格的字符串format写法
后面的是Python2.7推荐的写法。但是可以传入 --keep-percent-format
忽略这类修改。
Unicode literals
在Python3中,u'foo'其实已经是字符串的'foo',默认是不会修改这个类型数据的,除非传入 --py3-plus
或者 --py36-plus
:
Invalid escape sequences
现在flake8已经会检查出这个类型错误(W605):
is
/ isnot
is
/ isnot
从Python3.8开始会抛出SyntaxWarning错误,应该使用 ==
/ !=
替代:
pyupgrade会做如下替换:
ur
字符串文字
ur'...'
这种用法在python3已经不可用了:
数字的L后缀
在Python2数字后面会有L后缀,在Python3不再支持了:
八进制数字
这个最常见的用法是修改文件权限,在Python2中可以直接使用0755,但是Python3中这样是错误的:
pyupgrade会帮助修复这个问题:
super()
在Python3中,使用super不再需要手动传递self,传入 --py3-plus
或者 --py36-plus
会修复这个问题。
新式类
Python3 中只有新式类,传入 --py3-plus
或者 --py36-plus
会修复这个问题。
移除six相关兼容代码
当完全迁移到Python3之后,就没必要兼容Python2了,可以传入 --py3-plus
或者 --py36-plus
去掉six相关代码:
目前还有 six.add_metaclass
这个点没有实现,其他的都可以了~
f-strings
这是我最喜欢的一个功能,现在迁移到Python3都会迁到Python3.6+,所以可以直接使用 --py36-plus
参数,字符串格式化不需要用str.format,而是直接用f-strings:
后记
项目地址: https://github.com/asottile/pyupgrade
我已经在酱厂最大的几个项目之一应用了pyupgrade,已经达到生产环境使用的标准,请放心使用~