一、类型注解说明
我们知道 Python 是一种动态语言,变量以及函数的参数是不区分类型。因此我们定义函数只需要这样写就可以了:
1 | def add(x, y): |
坏处就是对于别人代码,无法一眼判断出参数的类型,IDE 也无法给出正确的提示。所以python3.5+就提供了类型注解:
1 | def add(x: int, y: int) -> int: |
用 : 类型
的形式指定函数的参数类型,用 -> 类型
的形式指定函数的返回值类型。
Python 解释器并不会因为这些注解而提供额外的校验,没有任何的类型检查工作。也就是说,这些类型注解加不加,对你的代码来说没有任何影响。
类型注解的好处:
- 让别的程序员看得更明白。
- 让 IDE 了解类型,从而提供更准确的代码提示、补全和语法检查(包括类型检查)。
在函数的 __annotations__
属性中会有你设定的注解:
1 | def add(x: int, y: int) -> int: |
输出:
{'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
二、类型标注支持
1.函数参数以及返回值
1 | def add(x: int, y: int) -> int: |
2.变量(3.6+后支持)
1 | from typing import List |
3. Any类型
Any
是一种特殊的类型。静态类型检查器将所有类型视为与 Any
兼容,反之亦然, Any
也与所有类型相兼容。
这意味着可对类型为 Any
的值执行任何操作或方法调用,并将其赋值给任何变量:一般用于不确定的返回值上。
1 | from typing import Any |
4. object类型
与 Any
相似,所有的类型都是 object
的子类型。然而不同于 Any
,反之并不成立: object
不是 其他所有类型的子类型。
这意味着当一个值的类型是 object
的时候,类型检查器会拒绝对它的几乎所有的操作。把它赋值给一个指定了类型的变量(或者当作返回值)是一个类型错误。比如说:
1 | def fun(item: object) -> int: |
使用 object
示意一个值可以类型安全地兼容任何类型。使用 Any
示意一个值地类型是动态定义的。
三、高级用法
1.类型别名
类型别名通过将类型分配给别名来定义,用于简化复杂类型注解。
1 | from typing import Dict, Tuple, Sequence |
等同于以下注解:
1 | def broadcast_message( |
2.Callable
期望特定签名的回调函数的框架可以将类型标注为 Callable[[Arg1Type, Arg2Type], ReturnType]
。
1 | from typing import Callable |
3.多类型注解
1 | from typing import Union |
四、类型注解检测
通过 mypy 库来检验最终代码是否符合注解。mypy是一个Python命令行应用 (Python command line application ),可以轻松集成到我们的代码流中。
需要安装:pip isntall mypy
例如:test.py有以下内容
1 | tmp: int = "test" |
执行命令:mypy test.py
如果类型都符合,则不会有任何输出,否则就会给出类似输出:
test.py:1: error: Incompatible types in assignment (expression has type "str", variable has type "int")