类型提示
Python 3.5+ 支持类型提示(Type Hints),用于提高代码可读性和 IDE 支持。
0x01. 基本类型提示
# 基本类型注解
def greet(name: str) -> str:
return f'Hello, {name}!'
def add(a: int, b: int) -> int:
return a + b
# 变量注解
name: str = 'Alice'
age: int = 25
pi: float = 3.14
is_active: bool = True
# 没有返回值
def print_message(message: str) -> None:
print(message)
0x02. 复杂类型
typing 模块
from typing import List, Dict, Tuple, Set, Optional, Union, Any, Callable
# 列表
numbers: List[int] = [1, 2, 3]
names: List[str] = ['Alice', 'Bob']
# 字典
scores: Dict[str, int] = {'Alice': 90, 'Bob': 85}
config: Dict[str, Any] = {'debug': True, 'port': 8080}
# 元组
point: Tuple[float, float] = (10.0, 20.0)
record: Tuple[int, str, bool] = (1, 'Alice', True)
# 集合
unique_ids: Set[int] = {1, 2, 3}
# 可选类型(可能是 None)
def find_user(user_id: int) -> Optional[str]:
users = {1: 'Alice', 2: 'Bob'}
return users.get(user_id)
# 等价写法
def find_user(user_id: int) -> str | None: # Python 3.10+
users = {1: 'Alice', 2: 'Bob'}
return users.get(user_id)
# 联合类型
def process(value: Union[int, str]) -> str:
return str(value)
# 等价写法(Python 3.10+)
def process(value: int | str) -> str:
return str(value)
# 可调用对象
def apply(func: Callable[[int, int], int], a: int, b: int) -> int:
return func(a, b)
# 使用
def add(a: int, b: int) -> int:
return a + b
result = apply(add, 3, 4) # 7
Python 3.9+ 泛型语法
# Python 3.9+ 可以直接使用内置类型
numbers: list[int] = [1, 2, 3]
scores: dict[str, int] = {'Alice': 90}
point: tuple[float, float] = (10.0, 20.0)
unique: set[int] = {1, 2, 3}
# Python 3.10+ 联合类型
def process(value: int | str) -> str:
return str(value)
# Python 3.10+ 可选类型
def find_user(user_id: int) -> str | None:
return None
0x03. 泛型
from typing import TypeVar, Generic
# TypeVar - 类型变量
T = TypeVar('T')
def first_element(lst: list[T]) -> T:
return lst[0]
# 使用
num = first_element([1, 2, 3]) # 推断为 int
text = first_element(['a', 'b']) # 推断为 str
# 约束类型变量
T = TypeVar('T', int, float, str)
def add(a: T, b: T) -> T:
return a + b
# 泛型类
from typing import Generic, TypeVar
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 peek(self) -> T:
return self._items[-1]
# 使用
int_stack: Stack[int] = Stack()
int_stack.push(1)
int_stack.push(2)
str_stack: Stack[str] = Stack()
str_stack.push('a')
str_stack.push('b')
0x04. 高级类型
TypedDict
from typing import TypedDict
# 定义字典结构
class UserDict(TypedDict):
name: str
age: int
email: str
# 使用
user: UserDict = {
'name': 'Alice',
'age': 25,
'email': 'alice@example.com'
}
# 可选字段
class UserDictOptional(TypedDict, total=False):
name: str
age: int
email: str # 所有字段都可选
# 混合必需和可选字段
class UserDictMixed(TypedDict):
name: str # 必需
age: int # 必需
class UserDictComplete(UserDictMixed, total=False):
email: str # 可选
phone: str # 可选
Literal
from typing import Literal
# 字面量类型
def set_direction(direction: Literal['up', 'down', 'left', 'right']) -> None:
print(f'Direction: {direction}')
set_direction('up') # OK
set_direction('forward') # 类型检查器会报错
# 数字字面量
def set_port(port: Literal[80, 443, 8080]) -> None:
print(f'Port: {port}')
# 组合字面量
LogLevel = Literal['debug', 'info', 'warning', 'error']
Final
from typing import Final
# 常量
MAX_SIZE: Final[int] = 100
PI: Final[float] = 3.14159
# 不能重新赋值(类型检查器会警告)
# MAX_SIZE = 200 # Error
# Final 类(不能被继承)
from typing import Final
class Immutable:
pass
class Child(Immutable): # 类型检查器会警告
pass
0x05. 类别类型
Type
from typing import Type
class Animal:
def speak(self) -> str:
return '...'
class Dog(Animal):
def speak(self) -> str:
return 'Woof!'
# 接受类本身(不是实例)
def create_animal(animal_type: Type[Animal]) -> Animal:
return animal_type()
# 使用
dog = create_animal(Dog)
print(dog.speak()) # Woof!
ClassVar
from typing import ClassVar
class MyClass:
# 类变量
count: ClassVar[int] = 0
def __init__(self) -> None:
MyClass.count += 1
# 类型检查器会确保 count 是类变量
obj1 = MyClass()
obj2 = MyClass()
print(MyClass.count) # 2
0x06. 类型别名
from typing import List, Dict, Tuple, Union
# 类型别名
Vector = List[float]
Matrix = List[Vector]
UserId = int
UserName = str
UserMap = Dict[UserId, UserName]
# 使用
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
# Python 3.10+ 新语法
type Vector = list[float]
type Matrix = list[Vector]
# 复杂类型别名
Coordinate = Tuple[float, float]
BoundingBox = Tuple[Coordinate, Coordinate]
JSON = Union[str, int, float, bool, None, Dict[str, 'JSON'], List['JSON']]
0x07. 协议(Protocol)
from typing import Protocol
# 定义协议(结构化子类型)
class Drawable(Protocol):
def draw(self) -> None: ...
# 实现协议的类
class Circle:
def draw(self) -> None:
print('Drawing circle')
class Square:
def draw(self) -> None:
print('Drawing square')
# 使用协议类型
def render(shape: Drawable) -> None:
shape.draw()
# Circle 和 Square 都符合 Drawable 协议
render(Circle()) # OK
render(Square()) # OK
0x08. 类型检查工具
mypy
# 安装
pip install mypy
# 运行检查
mypy script.py
mypy src/
# 配置 mypy.ini
[mypy]
python_version = 3.11
warn_return_any = True
warn_unused_configs = True
pyright
# VS Code 扩展
# 安装 Pylance 扩展
# 配置 pyrightconfig.json
{
"pythonVersion": "3.11",
"typeCheckingMode": "basic"
}
0x09. 实际应用
API 类型安全
from typing import TypedDict, Optional
from dataclasses import dataclass
# API 响应类型
class ApiResponse(TypedDict):
status: int
message: str
data: Optional[dict]
# 数据模型
@dataclass
class User:
id: int
name: str
email: str
age: Optional[int] = None
def get_user(user_id: int) -> ApiResponse:
user = User(id=user_id, name='Alice', email='alice@example.com')
return {
'status': 200,
'message': 'Success',
'data': {'user': user.__dict__}
}
配置类型
from typing import TypedDict, Literal
from pathlib import Path
class DatabaseConfig(TypedDict):
host: str
port: int
username: str
password: str
class AppConfig(TypedDict):
debug: bool
log_level: Literal['DEBUG', 'INFO', 'WARNING', 'ERROR']
database: DatabaseConfig
static_dir: Path
config: AppConfig = {
'debug': True,
'log_level': 'DEBUG',
'database': {
'host': 'localhost',
'port': 5432,
'username': 'admin',
'password': 'secret'
},
'static_dir': Path('/var/www/static')
}
验证器
from typing import TypeVar, Callable, Any
from functools import wraps
T = TypeVar('T')
def validate(**validators: Callable[[Any], bool]) -> Callable:
def decorator(func: Callable[..., T]) -> Callable[..., T]:
@wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> T:
# 验证逻辑
for name, validator in validators.items():
if name in kwargs and not validator(kwargs[name]):
raise ValueError(f'Invalid value for {name}')
return func(*args, **kwargs)
return wrapper
return decorator
# 使用
@validate(age=lambda x: 0 <= x <= 150)
def create_user(name: str, age: int) -> dict:
return {'name': name, 'age': age}
# create_user('Alice', age=25) # OK
# create_user('Bob', age=200) # ValueError
参考
目录