什么是Mypy

Mypy是Python的可选静态类型检查器。您可以在Python程序中添加类型提示(PEP 484),并使用mypy进行静态类型检查。查找程序中的错误,甚至不运行它们!

安装Mypy

Mypy需要运行Python 3.5或更高版本。下面代码是用的Python 3.7 使用pip安装mypy:

1
$ python3 -m pip install mypy

看几个简单例子: 平时我们代码大概都是下面的样子

1
2
3
4
# 参数name的类型是未知的
# 返回的类型也是未知的
def greeting(name):
    return 'Hello ' + name

稍微修改一些

1
2
3
4
5
6
7
# 参数name后面跟了:str 代表name期望是str类型
# 参数括号后面跟了->str代表返回类型为str类型
def greeting(name: str) -> str:
    return 'Hello ' + name
x: str = 'xxx' # 声明一个变量为str类型
greeting(x) # Hello xxx
greeting(123) # TypeError: can only concatenate str (not "int") to str

到目前为止仅有str、float等基本类型,使用list、tuple复杂类型需要引用typing中的类型

LIST

数组类型

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

# 参数names为list类型并且元素都是str类型
# 返回为None
def greet_all(names: List[str]) -> None:
    for name in names:
        print('Hello ' + name)

names = ["Alice", "Bob", "Charlie"]
ages = [10, 20, 30]

greet_all(names)   # Ok!
greet_all(ages)    #出错了 Error due to incompatible types 

Dict

字典类型

1
2
3
4
5
6
7
from typing import Dict

# Dict[int, str] int代表key类型, str代表val类型
def test(t: Dict[int, str]) -> Dict:
    return t

test({1: '234'}) # {1: '234'}

Iterable

可以迭代类型包括 List、Set、Tuple、Str、Dict

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def greeting(names: Iterable[str]) -> None:
    for name in names:
        print(name)

greeting(['aaa', 'bbb']) # list aaa bbb
greeting(('ccc', 'ddd')) # tuple ccc ddd
greeting({'eee', 'fff'}) # set eee fff
greeting({'ggg': 'hhh'}) # dict ggg
greeting('123') # str 1 2 3 
greeting(678) # error: Argument 1 to "greeting" has incompatible type "int"; expected "Iterable[str]"

Union

接受多个指定类型,但不接受除此外的类型

1
2
3
4
5
6
7
8
9
from typing import Union
# user_id 只能为int或者str
def normalize_id(user_id: Union[int, str]) -> str:
    if isinstance(user_id, int):
        return 'user-{}'.format(100000 + user_id)
    else:
        return user_id
normalize_id(1) # user-100001
normalize_id('2') # 2

Optional

可选类型,给参数设置默认值

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

# Optional[str]只是Union [str,None]的简写或别名。它主要是为了方便帮助功能签名看起来更清洁
# Optional[str, int] 只能包含一个类型, 这样是不正确的
def greeting(name: Optional[str] = None) -> str:
    if name is None:
        name = 'stranger'
    return 'Hello, ' + name
greeting() # Hello, stranger
greeting('123') # Hello, 123

Any

有时候我们不确定是什么类型的时候可以用到Any

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

def greeting(name: Any = None) -> str:
    if name is None:
        name = 'stranger'

    return 'Hello, ' + str(name)

greeting() # Hello, stranger
greeting('123') # Hello, 123
greeting(234) # Hello, 234
greeting([345]) # Hello, [345]

TypeVar

自定义类型

1
2
3
4
5
6
7
from typing import TypeVar

T = TypeVar('T') # 任意类型
A = TypeVar('A', int, str) # A类型只能为int或str
def test(t: A) -> None:
    print(t)
test(1)