Python中的类型标注

类型标注

类型标注,称为 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 模块中定义的类型,用户定义的类。除此之外,还可以是 NoneAnyUnionTupleCallable 等类型。

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.

参考链接

觉得有用可以请作者喝杯咖啡呀~
0%