类型标注
类型标注,称为 Type Hints 或者 Type annotation,由以下几个 PEP 定义:
- PEP 3107,Python 3.0,增加了 function annotation syntax,但没有实现该语义;
- PEP 484,Python 3.5,增加了 provisional module 以支持该特性;
- PEP 526,Python 3.6,增加了 variable annotations syntax。
与静态语言的类型声明相比,Python 中的类型标注不会在运行时做类型检查。
基本语法
function annotation
1
2
| def greeting(name:str, age: int = 13) - > str:
return 'Hello'+ name + str(age)
|
类型标注可接受的类型有:内置类(包括标准库和第三方库中定义的类)、抽象基类、types
模块中定义的类型,用户定义的类。除此之外,还可以是 None
、Any
、 Union
、 Tuple
和 Callable
等类型。
variable annotation
全局变量声明,只声明但没有初始化的变量,在引用时会报错。
1
2
| some_number: int # variable without initial value
some_list: List[int] = [] # variable with initial value
|
类变量声明
1
2
3
4
| class BasicStarship:
captain: str = 'Picard' # instance variable with default
damage: int # instance variable without default
stats: ClassVar[Dict[str, int]] = {} # class variable
|
ClassVar 是 Python 3.5 引入的 typing 模块中定义的。
类型检查工具
可以使用 mypy、pytype 等工具按照类型标注对代码进行检查。
PEP563
如下代码使用了类型标注,mypy 检查没有问题,但运行时会报错 NameError: name 'Subject' is not defined
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| from typing import Union
from dataclasses import dataclass
import pymysql.cursors
connection = pymysql.connect(host='localhost',
user='root',
password='',
db='test',
charset='utf8mb4')
@dataclass
class Subject:
id: int
cat_id: int
title: str
kind: int = 0
@classmethod
def get(cls, id: int) -> Union[Subject, None]:
with connection.cursor() as cursor:
cursor.execute(
"select id, cat_id, title, kind from subject where id=%s", id)
rs = cursor.fetchone()
if not rs:
return None
return cls(*rs)
|
原因是类型注解部分求值太早了,那个时候类还没创建完!,详见 PEP 563。解决方案有三种:
Python 3.7 延迟求值
如果 Python 是 3.7 版本,可以在文件开头加入:
1
| from __future__ import annotations
|
以启用延迟求值的特性。
使用字符串代替类名
将 get 方法中类名改为用字符串代替,参考 PEP484 中的讨论
1
2
| def get(cls, id: int) -> Union['Subject', None]:
...
|
使用 pytype 做静态检查
pytype 还能够推断未做类型标注的 Python 代码的类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
| ➜ cat foo.py
def make_greeting(user_id):
return 'hello, user' + user_id
def print_greeting():
print(make_greeting(0))
➜ pytype-single foo.py
File "foo.py", line 2, in make_greeting: unsupported operand type(s) for +: 'str' and 'int' [unsupported-operands]
Function __add__ on str expects str
Called from (traceback):
line 5, in print_greeting
For more details, see https://github.com/google/pytype/blob/master/docs/errors.md#unsupported-operands.
|
参考链接