以下所有例子都參考了最新版本的 Python 文檔與 mypy 文檔
必備條件
安裝最新版本的 Python 和 mypy
要學(xué)會按需配置自己的編輯器草讶,比如我的 VSCode 就裝好了 Python 和 Pyright 擴(kuò)展
變量
age: int = 1
child: bool
if age < 18:
child = True
else:
child = False
常量
from typing import Final
RATE: Final = 3000
class Base:
DEFAULT_ID: Final = 0
RATE = 300 # Error: can't assign to final attribute
Base.DEFAULT_ID = 1 # Error: can't override a final attribute
內(nèi)置類型
from typing import List, Set, Dict, Tuple, Optional
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}
# 字典需要寫出 key 和 value 的類型
x: Dict[str, float] = {"field": 2.0}
# 元組需要寫出所有元素的類型
x: Tuple[int, str, float] = (3, "yes", 7.5)
# 用 Optional[] 表示可以為 None 的類型
x: Optional[str] = some_function()
# mypy 可以推斷出 if 語句里 x 不能為 None
if x is not None:
print(x.upper())
# 如果 x 的值不可能為 None, 用 assert
assert x is not None
print(x.upper())
函數(shù)
from typing import Callable, Iterator, Union, Optional, List
def stringify(num: int) -> str:
return str(num)
def plus(num1: int, num2: int) -> int:
return num1 + num2
def f(num1: int, my_float: float = 3.5) -> float:
return num1 + my_float
# callable (函數(shù)) 類型
x: Callable[[int, float], float] = f
# 生成器函數(shù)會返回可迭代的元素
def g(n: int) -> Iterator[int]:
i = 0
while i < n:
yield i
i += 1
類
from typing import ClassVar
class MyClass:
attr: int
# 實(shí)例變量可以有默認(rèn)值
charge_percent: int = 100
# 什么也不返回凹炸,就是返回 None
def __init__(self) -> None:
...
# 實(shí)例方法减响,省略 self 的類型
def my_method(self, num: int, str1: str) -> str:
return num * str1
# 類可以用作類型
x: MyClass = MyClass()
# 類變量
class Car:
seats: ClassVar[int] = 4
passengers: ClassVar[List[str]]
# 需要注意還沒定義就使用一個(gè)類會報(bào)錯
def f(foo: A) -> int: # Error
...
class A:
...
# 你可以使用字符串的形式來規(guī)避
def f(foo: "A") -> int: # OK
...
Named tuples 命名元組
from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
p = Point(x=1, y="x") # Error: Argument has incompatible type "str"; expected "int"
異步迭代器
from typing import AsyncIterator
async def gen() -> AsyncIterator[bytes]:
lst = [b async for b in gen()] # 推斷類型是 "List[bytes]"
yield "no way" # Error: Incompatible types (got "str", expected "bytes")
類型別名
AliasType = Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]]
def f() -> AliasType:
...
Dataclasses 數(shù)據(jù)類
from dataclasses import dataclass, field
@dataclass
class Application:
name: str
plugins: List[str] = field(default_factory=list)
test = Application("Testing...") # OK
bad = Application("Testing...", "with plugin") # Error: List[str] expected
泛型
from typing import TypeVar, Generic
T = TypeVar("T")
class Stack(Generic[T]): # 泛型
def __init__(self) -> None:
self.items: List[T] = []
def push(self, item: T) -> None:
self.items.append(item)
def pop(self) -> T:
return self.items.pop()
def empty(self) -> bool:
return not self.items
# Stack[int] 實(shí)例
stack = Stack[int]()
stack.push(2)
stack.pop()
stack.push("x") # Type error
Literal types
PrimaryColors = Literal["red", "blue", "yellow"]
SecondaryColors = Literal["purple", "green", "orange"]
AllowedColors = Literal[PrimaryColors, SecondaryColors]
def paint(color: AllowedColors) -> None: ...
paint("red") # OK
paint("turquoise") # Error
Protocol 協(xié)議
實(shí)現(xiàn)結(jié)構(gòu)化子類型(靜態(tài)鴨子類型)陪竿,可以當(dāng)成接口一樣用沛善。
from typing import Iterable, Protocol
class SupportsClose(Protocol):
def close(self) -> None:
... # 函數(shù)體可以為空 (explicit '...')
class Resource: # 沒有寫 SupportsClose
def close(self) -> None:
self.resource.release()
def close_all(items: Iterable[SupportsClose]) -> None:
for item in items:
item.close()
close_all([Resource(), open("some/file")]) # OK
Abstractmethod 抽象方法
方法可以有默認(rèn)的實(shí)現(xiàn)铣墨,但是抽象方法規(guī)定必須在子類中實(shí)現(xiàn)弟灼。
from typing import Protocol
from abc import abstractmethod
class Example(Protocol):
def first(self) -> int:
return 42
@abstractmethod
def second(self) -> int: # 沒有默認(rèn)實(shí)現(xiàn)
raise NotImplementedError # 防止這個(gè)方法被調(diào)用
Enum 枚舉
如果要像 C 語言一樣定義枚舉的話,也是用類來實(shí)現(xiàn)的徙缴。
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
print(Color.RED)
這樣就能用類當(dāng)成枚舉一樣用了试伙。