以前写过关于python类型校验的相关总结,但是不怎么全面,有些不常见的特殊情况并未被记录。

任意类型any

若声明某函数时指定函数传入参数的数据类型为any,则调用该函数时该参数的参数类型可以为任意类型。

1
2
3
4
def demo(name: any, age: 'int > 0' = 20) -> str:  # ->str 表示该函数的返回值是str类型的
print(name, type(name))
print(age, type(age))
return "hello world"

类型别名

1
2
3
4
5
6
7
# 给List[float]类型取个别名为Vector
Vector = List[float]

def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]

new_vector = scale(2.0, [1.0, -4.2, 5.4])

内容与长度限制

在需要限制声明变量的长度以及包含类型的时候可以这样做:

1
2
3
from typing import Tuple

version: Tuple[int, int, int] = (3, 7, 4)

泛型与嵌套类型

类型结构包含多种样式的时候可以使用泛型与嵌套类型的方式处理

1
2
3
var: List[int or float] = [2, 3.5] # 泛型
var: List[List[int]] = [[1, 2], [2, 3]] # 嵌套类型
person: Tuple[str, int, float] = ('Mike', 22, 1.75)

Dict、Mapping、MutableMapping / Set、AbstractSet

在需要声明字典类型的时候需要十分注意,因为根据官方文档,Dict 推荐用于注解返回类型,Mapping 推荐用于注解参数。它们的使用方法都是一样的,其后跟一个中括号,中括号内分别声明键名、键值的类型.

因此以下写法是不规范的,容易引起编辑器警告:

1
2
def testfun(dict_info:Dict[str,int]={"key":1}):
pass

正确写法如下:

1
2
def size(rect: Mapping[str, int]) -> Dict[str, int]:
return {'width': rect['width'] + 100, 'height': rect['width'] + 100}

set亦如此

1
2
def describe(s: AbstractSet[int]) -> Set[int]:
return set(s)

Sequence

Sequence是一个泛型,其本身不需要去指定究竟是List还是tuple,用法与List类似

1
2
def square(elements: Sequence[float]) -> List[float]:
return [x ** 2 for x in elements]

无返回内容

当函数没有返回内容的时候也可以进行注解

1
2
def hello() -> NoReturn:
print('hello')

TypeVar

当使用场景当中某个返回变量可以是多种类型,但不能是某些少数类型的时候,可以采用TypeVar

1
2
3
4
5
6
# 例如一个人的身高,便可以使用 int 或 float 或 None 来表示,但不能用 dict 来表示,所以可以这么声明:

height = 1.75
Height = TypeVar('Height', int, float, None)
def get_height() -> Height:
return height

Union

Union,联合类型,Union[X, Y] 代表要么是 X 类型,要么是 Y 类型。但是不能是两者混用。

1
Union[Union[int, str], float] == Union[int, str, float]

Optional

Optional:意思是说这个参数可以为空或已经声明的类型,即 Optional[X] 等价于 Union[X, None]。

在参数传递的时候某些参数不一定非要传值,这时候Optional作为一种可选类型非常好用。

Generator

如果想代表一个生成器类型,可以使用 Generator,它的声明比较特殊,其后的中括号紧跟着三个参数,分别代表 YieldType、SendType、ReturnType,如:

1
2
3
4
5
6
7
8
from typing import Generator


def echo_round() -> Generator[int, float, str]:
sent = yield 0
while sent >= 0:
sent = yield round(sent)
return 'Done'

在这里 yield 关键字后面紧跟的变量的类型就是 YieldType,yield 返回的结果的类型就是 SendType,最后生成器 return 的内容就是 ReturnType。

当然很多情况下,生成器往往只需要 yield 内容就够了,我们是不需要 SendType 和 ReturnType 的,可以将其设置为空,如:

1
2
3
4
5
6
7
from typing import Generator


def infinite_stream(start: int) -> Generator[int, None, None]:
while True:
yield start
start += 1