Python 添加类型标注 | 散发着自由松散气息的代码
Python 如此简洁,书写者在声明变量时甚至无需考虑类型 。
但是简洁与复杂间 ,是存在一个平衡点的。当我们书写较为复杂的项目时,还是希望可以拥有「静态类型语言」强大的类型检查和智能的提示。
好消息是,并不需要像 TypeScript 那样 ,引入一个新的编译器来给 JavaScript 做“升级”来进行类型检查, Python 自带的 typing 工具可以在一定程度上把 Python 变成「静态类型语言」;坏消息是, Python 归根结底不是「静态类型语言」 ,经过我的简单测试,其代码还是「自由松散」的 。
给 Python 标注类型
首先和读者声明我们的实验环境。
❯ python --version Python 3.7.0
本文参考了 Python3.7 的 中文文档 。
我们声明一个变量,通过如下方式声明类型:
a: int = 1 b: float = .2 print(f'{a}, {b}') # 1, 0.2
遗憾的是 ,在 Python 中 ,
a: int = 1这句话并没什么意义,说的直白点,就是『脱裤子放屁』;再说得好听点 , Python 的类型标注放在这里这么用完全没有必要 。
首先,
a = 1中解释器会自动把
a推断为
int类型,诸如 Pylance 的 Language Server 也会在我们书写时提供
int的方法补全。
此外 ,就算我们把
a的类型规定为
int,然后将
str赋给
a,解释器和 Language Server 也完全不会报错。如下 。
a: int a = '1' print(a) # 非常迷
做上述类型检查对于现代编译技术而言应该是毫无难度的 ,但这里就是没有报错 、没有警告 。这大概与 Python 的设计哲学有关。
我们看看 TypeScript 是如何表现的:
TypeScript 把自己当作静态类型语言,要求书写时就确保类型的正确性。
使用 typing
尽管 Python 并不强制要求类型的正确性,并且会自动帮我们做强类型转换 ,但是我们依旧可以享受类型标注带来的诸多便利 。
比如,我们现在要定义一个函数
foo,函数返回一个列表
dogList,列表中的元素都是我们自定义的类
Dog的实例。
如果没有类型标注 ,我们无法获得智能提示,如下。
Python 中从来就不要求
List对象中的元素都是同一类型,因此 ,解释器或者 Language Server 也不会「吃力不讨好」般地去把程序运行一遍,然后推断你这个 List 里放的东西是什么类型 。
自然,当你从
List中拿元素时(比如上述的
dogList[0]) ,它没法告诉你
List中你拿的元素是什么类型,也就没办法提示(No suggestion.)。
这与实际业务场景不符,因为我们写代码时 ,在一个列表中装入的往往都是同一类型。 为了在取元素时获得补全提示,我们可以使用
typing.List+
极简的泛型。如下。
我们规定,
foo返回的元素必是一个
List,且其中元素类型是
Dog类型。然后我们的
dogList[0]也被识别成了
Dog类型,获得了补全 。舒服。
题外话:聪明的 Pylance
其实 Pylance 自己也可以做一些类型推导。比如我们使用生成器生成列表时, Pylance 就会判断这个列表中元素属于什么类型:
结语
关于
typing的用法 ,还有很多内容可以讨论 ,我的参考资料主要是:Python3.7 的 typing中文文档 。此外,用 Python 泛型实现函数重载相比静态类型语言似乎十分麻烦(我参考了Python实用宝典的文章(知乎)),如果之后我遇到合适的场景也会成文分享 。
我是小拍 ,感谢关注!