缘起
Python是一门动态强类型语言, 动态性是它鲜明的特点.
但是动态性在给程序员充分的自由的同时, 也带来了一些不好的负面效应. 特别是在团队协作的时候, 不好的队友会引发许多难以定位的问题.
同时动态性也大大削弱了ide的作用, 代码提示, 重构等一些功能远不如静态语言来得可靠.
1 | class Person: |
比如这个代码片段, ide很难准确识别introduce_someone
的参数应该是Person
类的实例, 它只能单纯地从文本上分析, 并把所有可能的单词都提示出来.
而且当调用introduce_someone
, 传入了不合适的对象, 也很难通过静态检查发现.
类型标记的出现就解决了这些问题.
性空
类型标记就是, 给变量, 参数, 函数附加上类型信息. 类似Java等静态语言的变量声明信息.
Python 从3.5开始, 引入了类型标记系统, 并在后面的版本有所增强.
类型标记的基本语法 变量名: 标记
, 标记可以是字符串, 对象或者Type aliases
(类型别名)
变量类型标记
1 | name: str = 'tom' |
函数类型标记
1 | class Person: |
函数的类型标记比变量多了一项: 返回值, 通过->
与函数名连接在一起.
如果调用introduce_someone
, 参数不是Person
类的实例. 静态检查会发现以下错误.1
2error: Argument 1 to "introduce_someone" has incompatible type "str"; expected "Person"
Found 1 error in 1 file (checked 1 source file)
mypy
mypy 实用工具是一款针对 Python 的静态类型检查程序, 也可以和pytest一起配合使用.
安装
1 | pip install mypy |
执行检查
1 | mypy my_program.py my_src_folder |
typing库
Python内置typing库提供了许多有用的工具来辅助类型标记
类型别名 Type aliases
类型别名(运行时的标识函数), 帮助更好地进行类型标记, 这些别名可以进行组合.
1 | from typing import List, Dict, Tuple, Sequence |
静态检查结果, 三个调用错误都发现了1
2
3
4
5error: List item 0 has incompatible type "str"; expected "float"
error: Dict entry 0 has incompatible type "str": "int"; expected "str": "str"
error: Argument 1 to "print_address" has incompatible type "List[object]"; expected "Tuple[str, int]"
Found 3 errors in 1 file (checked 1 source file)
NewType
使用 NewType() 辅助函数创建派生的类型标记.
静态类型检查器会将新类型视为它是原始类型的子类, 可用于发现逻辑错误(比如: 虽然都是数字, 其实含义不同)
1 | from typing import NewType |
Callable
标记为可调用对象, 期望特定签名的回调函数的框架可以将类型标注为 Callable[[Arg1Type, Arg2Type], ReturnType]。
例如:1
2
3
4
5
6
7
8from typing import Callable
def feeder(get_next_item: Callable[[], str]) -> None:
# Body
def async_query(on_success: Callable[[int], None],
on_error: Callable[[int, Exception], None]) -> None:
# Body
TypeVar
通过TypeVar来定义一个泛型类型标记, 限制对象的可选类型
1 | from typing import TypeVar |
Any 类型
Any 是一种特殊的类型。
静态类型检查器将所有类型视为与 Any 兼容,反之亦然, Any 也与所有类型相兼容。
所有返回值无类型或形参无类型的函数将隐式地默认使用 Any 类型(没有类型标记的代码, 模式标记就是Any)
1 | from typing import Any |
其他
- 分离的hint信息(typing stubs) https://peps.python.org/pep-0561/