python Type Hint

引入

​ 在C语言中每使用一个变量前要先将其声明,如 int a =1,float b =3.14。这么做的好处有2个,一是在之后代码中无需“猜测”变量到底是什么类型,声明是什么就是什么,这就是静态变量。二是少了“猜测”这一步,代码执行效率会有所提升。python默认所有的变量都是动态的,所以你无需提前声明类型,写出了一个变量a,赋值给他一个常数、列表、字典等等都可以。当然动态所带来的问题就是,在代码执行的时候需要去“猜测”变量的类型,从而降低了运行效率。

​ 在python3.5及之后版本,python加入了模块typing,它允许在你命名变量的时候设定它的类型,抽象出来它长这个样子:variable : type,在设定一个变量类型为常量(int)之后并不会影响你给他赋值为字符串(str),这种类型设定如名字一样是类型暗示(Type Hint),而不是决定。

​ 有一个名为mypy的包可以显式的帮你找出你在类型上的问题:

1
2
pip install mypy
$ mypy program.py

介绍

可供使用的类型:

Type Description
int integer
float floating point number
bool boolean value
str string (unicode)
bytes 8-bit string
object an arbitrary object (object is the common base class)
List[str] list of str objects
Tuple[int, int] tuple of two int objects (Tuple[()] is the empty tuple)
Tuple[int, ...] tuple of an arbitrary number of int objects
Dict[str, int] dictionary from str keys to int values
Iterable[int] iterable object containing ints
Sequence[bool] sequence of booleans (read-only)
Mapping[str, int] mapping from str keys to int values (read-only)
Any dynamically typed value with an arbitrary type
Union[T1, ..., Tn] Union[int, str]both integers and strings are valid argument values.

方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from typing import List, Set, Dict, Tuple, Optional, Union, Any
x: int = 1
x: float = 1.0
x: bool = True
x: str = "test"
x: bytes = b"test"
x: List[int] = [1]
x: Set[int] = {6, 7}
x: Dict[str, float] = {'field': 2.0}
x: Tuple[int, str, float] = (3, "yes", 7.5)
x: List[Union[int, str]] = [3, 5, "test", "fun"]

def plus(num1: int, num2: float) -> float:
return num1 + num2

def f(x: Union[int, str]) -> Any:
if isinstance(x, int):
# Here type of x is int.
return (x + 1) # OK
else:
# Here type of x is str.
return (x + 'a') # OK
1
2
3
4
5
6
def join(string_list): #定义一个方法,不做类型设定
return ', '.join(string_list)
>>> join('hello')
'h, e, l, l, o'
>>> join(['hello','world'])
'hello, world'

对于这个函数,期望的结果就是会把[‘hello’, ‘world’]变成’hello, world’。 但是如果不小心没有传list而是传了一个字符串’hello’,这段代码也不会报错,只是会返回’h, e, l, l, o’这个并不期望的结果。

1
2
3
4
5
6
7
8
9
10
11
from typing import List

def join(string_list: List[str]) -> str:
return ', '.join(string_list)
#string_list 局部变量名, List[str] 局部变量类型, str 返回结果类型
>>> join('hello') #虽然不期待,但是仍可以运行
'h, e, l, l, o'
>>> join(['hello','world'])
'hello, world'
>>> join.__annotations__
{'string_list': typing.List[str], 'return': <class 'str'>}

这样声明函数有一个好处,就是不需要在注释里面说明变量类型,更加直观。Python把这种类型的声明看成是一种对函数的注解(annotation),而注解本身并不具有任何的意义,也不影响运行的过程。与没有注解的版本差别就是多了一个annotations的字段 。

1
2
3
4
5
6
from typing import List

def join(string_list: List[str]) -> str:
return ', '.join(string_list)

print(join('hello'))

运行以及使用mypy检查,代码可以运行,mypy也可以给出提示

1
2
3
4
$ python3 test_mypy.py
h, e, l, l, o
$ mypy test_mypy.py
test_mypy.py:6: error: Argument 1 to "join" has incompatible type "str"; expected List[str]