python typing 模块
# 基础知识
Python的typing模块提供了类型提示(Type Hints)功能,用于在代码中标注变量、函数参数和返回值的类型。这些类型提示不会影响代码的运行时行为,但可以帮助IDE、类型检查器和开发者更好地理解代码。
# 基本概念
from typing import Any, Union, Optional, List, Dict, Tuple, Callable
# 基本类型注解
def greet(name: str) -> str:
return f"Hello, {name}"
# 变量类型注解
age: int = 25
scores: List[float] = [95.5, 87.2, 92.1]
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 基础类型
# 1. 基本类型注解
# 基本数据类型
def process_data(
text: str,
number: int,
decimal: float,
flag: bool,
data: bytes
) -> str:
return f"{text}: {number + decimal} ({flag})"
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 2. 容器类型
from typing import List, Dict, Tuple, Set
# 列表类型
def process_list(items: List[str]) -> List[int]:
return [len(item) for item in items]
# 字典类型
def process_dict(data: Dict[str, int]) -> Dict[int, str]:
return {v: k for k, v in data.items()}
# 元组类型
def process_tuple(coords: Tuple[float, float]) -> Tuple[int, int]:
return (int(coords[0]), int(coords[1]))
# 集合类型
def process_set(numbers: Set[int]) -> Set[str]:
return {str(n) for n in numbers}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 3. 可选类型 (Optional)
from typing import Optional
def find_user(user_id: int) -> Optional[str]:
users = {1: "Alice", 2: "Bob"}
return users.get(user_id) # 可能返回None
# 带默认值的可选参数
def greet_user(name: Optional[str] = None) -> str:
if name is None:
return "Hello, Guest"
return f"Hello, {name}"
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 联合类型 (Union)
聚合类型是指由多个其他类型组合而成的复合类型,它能够将多个不同类型的值组合成一个单一的数据结构。在不同的编程语言和上下文中,聚合类型有不同的表现形式
# 1. 基本用法
from typing import Union
# 接受多种类型的参数
def process_data(data: Union[str, bytes]) -> str:
if isinstance(data, bytes):
return data.decode('utf-8')
return data
# 返回多种类型
def get_value(key: str) -> Union[str, int, None]:
data = {"name": "Alice", "age": 30}
return data.get(key)
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 2. Python 3.10+ 简写语法
# 使用 | 操作符(Python 3.10+)
def process_data(data: str | bytes) -> str:
if isinstance(data, bytes):
return data.decode('utf-8')
return data
def get_value(key: str) -> str | int | None:
data = {"name": "Alice", "age": 30}
return data.get(key)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 泛型类型
# 1. 基本泛型
from typing import TypeVar, Generic, List, Dict
# 定义类型变量
T = TypeVar('T')
K = TypeVar('K')
V = TypeVar('V')
# 泛型类
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()
str_stack: Stack[str] = Stack()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 2. 约束泛型
from typing import TypeVar, Union
# 约束类型变量
Number = TypeVar('Number', bound=Union[int, float])
def add_numbers(a: Number, b: Number) -> Number:
return a + b
# 只能用于数字类型
result1 = add_numbers(5, 3) # int
result2 = add_numbers(3.14, 2.86) # float
# result3 = add_numbers("5", "3") # 类型错误
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 函数类型
# 1. Callable 类型
from typing import Callable, List
# 函数类型注解
def apply_func(func: Callable[[int], str], numbers: List[int]) -> List[str]:
return [func(n) for n in numbers]
# 使用示例
def int_to_str(n: int) -> str:
return str(n)
result = apply_func(int_to_str, [1, 2, 3, 4, 5])
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 2. 复杂函数签名
from typing import Callable, TypeVar, Union
T = TypeVar('T')
# 带泛型的函数类型
Processor = Callable[[T], str]
OptionalProcessor = Callable[[T], Union[str, None]]
def process_with_handler(
data: T,
handler: Processor[T]
) -> str:
return handler(data)
# 使用示例
def format_number(n: int) -> str:
return f"Number: {n}"
result = process_with_handler(42, format_number)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 高级类型
# 1. Literal 类型
from typing import Literal
# 字面量类型
def get_status(status: Literal["success", "error", "pending"]) -> str:
return f"Status: {status}"
# 只能传入指定的字面量值
get_status("success") # 正确
get_status("error") # 正确
# get_status("unknown") # 类型错误
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 2. TypedDict
from typing import TypedDict, Optional
# 定义类型化字典
class UserInfo(TypedDict):
name: str
age: int
email: Optional[str]
# 使用类型化字典
def create_user(info: UserInfo) -> str:
return f"User {info['name']} is {info['age']} years old"
# 创建符合类型的字典
user_data: UserInfo = {
"name": "Alice",
"age": 30,
"email": "[email protected]"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 3. Protocol (结构化类型)
from typing import Protocol
# 定义协议(接口)
class Drawable(Protocol):
def draw(self) -> str: ...
class Circle:
def draw(self) -> str:
return "Drawing a circle"
class Square:
def draw(self) -> str:
return "Drawing a square"
# 接受任何实现了draw方法的对象
def render_shape(shape: Drawable) -> str:
return shape.draw()
# 使用示例
circle = Circle()
square = Square()
print(render_shape(circle)) # "Drawing a circle"
print(render_shape(square)) # "Drawing a square"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 特殊类型
# 1. Any 类型
from typing import Any
# Any 表示任意类型
def process_anything(data: Any) -> Any:
return data
# 通常用于与动态代码交互
def legacy_function(data: Any) -> str:
return str(data)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 2. NoReturn 类型
from typing import NoReturn
# 表示函数永远不会返回(总是抛出异常)
def raise_error(message: str) -> NoReturn:
raise ValueError(message)
def infinite_loop() -> NoReturn:
while True:
pass
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 3. Never 类型 (Python 3.11+)
from typing import Never
# Never 表示不可能的类型
def impossible_function() -> Never:
raise Exception("This function should never be called")
# 用于表示不可能的情况
def process_data(data: str | int) -> str:
if isinstance(data, str):
return data.upper()
elif isinstance(data, int):
return str(data)
else:
# 这里 data 的类型是 Never,因为前面的条件已经覆盖了所有可能
return impossible_function()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 类型别名
# 1. 基本类型别名
from typing import List, Dict, Union
# 创建类型别名
UserId = int
UserName = str
UserData = Dict[UserId, UserName]
UserList = List[UserData]
# 使用类型别名
def process_users(users: UserList) -> List[UserName]:
return [user_data[user_id] for user_data in users for user_id in user_data]
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 2. 复杂类型别名
from typing import Callable, List, Union
# 复杂的类型别名
Number = Union[int, float]
NumberProcessor = Callable[[Number], Number]
NumberList = List[Number]
# 使用复杂类型别名
def apply_operations(
numbers: NumberList,
operations: List[NumberProcessor]
) -> NumberList:
result = numbers
for op in operations:
result = [op(n) for n in result]
return result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 运行时类型检查
# 1. 使用 isinstance 和 issubclass
from typing import Union, get_args, get_origin
def check_type(obj: Any, expected_type: Any) -> bool:
"""检查对象是否符合预期类型"""
if expected_type is Any:
return True
# 处理 Union 类型
if get_origin(expected_type) is Union:
return any(isinstance(obj, t) for t in get_args(expected_type))
return isinstance(obj, expected_type)
# 使用示例
def process_data(data: Union[str, int]) -> str:
if not check_type(data, Union[str, int]):
raise TypeError(f"Expected str or int, got {type(data)}")
return str(data)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2. 类型验证装饰器
from typing import Callable, Any, get_type_hints
from functools import wraps
def validate_types(func: Callable) -> Callable:
"""类型验证装饰器"""
@wraps(func)
def wrapper(*args, **kwargs):
hints = get_type_hints(func)
# 验证参数类型
for (name, value), expected_type in zip(
list(zip(func.__code__.co_varnames, args)) + list(kwargs.items()),
list(hints.values())[:-1] # 排除返回类型
):
if not check_type(value, expected_type):
raise TypeError(f"Parameter {name} should be {expected_type}, got {type(value)}")
result = func(*args, **kwargs)
# 验证返回类型
return_type = hints.get('return')
if return_type and not check_type(result, return_type):
raise TypeError(f"Return value should be {return_type}, got {type(result)}")
return result
return wrapper
# 使用装饰器
@validate_types
def add_numbers(a: int, b: int) -> int:
return a + b
# 这会正常工作
result = add_numbers(5, 3)
# 这会抛出类型错误
# result = add_numbers("5", 3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 实际应用场景
# 1. API 开发 (FastAPI)
from typing import List, Optional
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
email: Optional[str] = None
tags: List[str] = []
class UserResponse(BaseModel):
user: User
status: str
def create_user(user_data: User) -> UserResponse:
# 处理用户创建逻辑
return UserResponse(user=user_data, status="created")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2. 数据处理管道
from typing import TypeVar, Callable, List, Union
from dataclasses import dataclass
T = TypeVar('T')
U = TypeVar('U')
@dataclass
class DataProcessor(Generic[T, U]):
transform: Callable[[T], U]
validate: Callable[[U], bool]
def process(self, data: List[T]) -> List[U]:
results = []
for item in data:
transformed = self.transform(item)
if self.validate(transformed):
results.append(transformed)
return results
# 使用示例
def transform_string(s: str) -> int:
return len(s)
def validate_length(n: int) -> bool:
return 0 <= n <= 100
processor = DataProcessor(transform_string, validate_length)
result = processor.process(["hello", "world", "python"])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 3. 配置管理
from typing import TypedDict, Optional, Union
class DatabaseConfig(TypedDict):
host: str
port: int
username: str
password: str
database: str
class CacheConfig(TypedDict):
enabled: bool
host: Optional[str]
port: Optional[int]
ttl: int
class AppConfig(TypedDict):
debug: bool
database: DatabaseConfig
cache: CacheConfig
log_level: Union[str, int]
def load_config() -> AppConfig:
return {
"debug": True,
"database": {
"host": "localhost",
"port": 5432,
"username": "user",
"password": "pass",
"database": "mydb"
},
"cache": {
"enabled": True,
"host": "localhost",
"port": 6379,
"ttl": 3600
},
"log_level": "INFO"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 最佳实践
# 1. 渐进式类型化
# 从简单开始,逐步添加类型
def simple_function(x, y):
return x + y
# 添加基本类型
def typed_function(x: int, y: int) -> int:
return x + y
# 添加更复杂的类型
def advanced_function(
x: Union[int, float],
y: Union[int, float],
operation: Callable[[Union[int, float]], str]
) -> str:
result = x + y
return operation(result)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2. 使用类型别名提高可读性
from typing import List, Dict, Union
# 定义有意义的类型别名
UserId = int
UserName = str
UserEmail = str
UserProfile = Dict[str, Union[str, int, bool]]
# 使用类型别名
def get_user_profile(user_id: UserId) -> UserProfile:
# 实现逻辑
pass
def update_user_name(user_id: UserId, name: UserName) -> bool:
# 实现逻辑
pass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 3. 合理使用 Optional 和 Union
from typing import Optional, Union
# 好的做法:明确表示可能为None
def find_user(user_id: int) -> Optional[str]:
users = {1: "Alice", 2: "Bob"}
return users.get(user_id)
# 好的做法:明确表示多种可能类型
def process_data(data: Union[str, bytes]) -> str:
if isinstance(data, bytes):
return data.decode('utf-8')
return data
# 避免过度使用Any
def bad_function(data: Any) -> Any: # 太宽泛
return data
def good_function(data: Union[str, int]) -> str: # 更具体
return str(data)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 常见陷阱和注意事项
# 1. 运行时类型检查
from typing import Union
# 错误:不能在运行时直接使用Union
def bad_check(data):
# 这会失败
return isinstance(data, Union[str, int])
# 正确:使用元组进行运行时检查
def good_check(data):
return isinstance(data, (str, int))
# 或者使用类型检查库
from typing import get_args, get_origin
def advanced_check(data, expected_type):
if get_origin(expected_type) is Union:
return any(isinstance(data, t) for t in get_args(expected_type))
return isinstance(data, expected_type)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2. 循环导入问题
# 使用字符串类型注解避免循环导入
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .models import User
def process_user(user: "User") -> str:
return user.name
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 3. 性能考虑
# 类型注解对运行时性能没有影响
# 但过多的类型检查可能影响性能
# 好的做法:在开发时使用类型检查,生产环境关闭
import os
if os.getenv("ENVIRONMENT") == "development":
# 启用类型检查
pass
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 工具和库
# 1. 类型检查器
# 安装 mypy
pip install mypy
# 运行类型检查
mypy your_file.py
# 配置 mypy
# mypy.ini
[mypy]
python_version = 3.8
warn_return_any = True
warn_unused_configs = True
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 2. IDE 支持
# 大多数现代IDE都支持类型提示
# PyCharm, VS Code, Vim/Neovim 等
# 类型存根文件 (.pyi)
# 用于为第三方库提供类型信息
1
2
3
4
5
2
3
4
5
# 3. 类型存根文件
# example.pyi
from typing import List, Optional
def process_data(data: List[str]) -> Optional[str]: ...
def get_config() -> dict: ...
1
2
3
4
5
2
3
4
5
这个文档涵盖了Python typing模块的主要功能和使用方法。你可以根据具体需求深入学习特定的部分。
上次更新: 2025/10/09, 21:06:25