如何让Python函数与另一个函数拥有相同的类型标注?
实现包装器的自动类型同步
1. 完全复制原函数的参数与返回类型
如果包装器只是原函数的简单转发,不需要修改返回值,可以通过PEP 612引入的ParamSpec和ReturnType自动复用原函数的类型签名,无需硬编码。
示例代码:
from typing import ParamSpec, ReturnType, cast import os # 定义参数规格和返回值类型变量 P = ParamSpec("P") R = ReturnType("R") def my_open(*args: P.args, **kwargs: P.kwargs) -> R: # 用cast辅助类型检查器确认返回值类型匹配 return cast(R, os.open(*args, **kwargs))
若包装器无额外逻辑,还能更简洁:
from typing import Callable, ParamSpec, ReturnType import os P = ParamSpec("P") R = ReturnType("R") my_open: Callable[P, R] = os.open
2. 保留参数类型,修改返回类型
对于像scoped_open这类需要保留原函数参数、但返回类型不同的场景,同样用ParamSpec捕获参数类型,ReturnType捕获原函数返回值类型,再组合成新的返回类型。
示例代码:
from typing import ParamSpec, ReturnType, Generator, contextmanager import os P = ParamSpec("P") R = ReturnType("R") @contextmanager def scoped_open(*args: P.args, **kwargs: P.kwargs) -> Generator[R, None, None]: fd = os.open(*args, **kwargs) try: yield fd finally: os.close(fd)
这里Generator[R, None, None]表示生成器会产出os.open的返回值类型,不接收外部值,也无最终返回值,完全符合上下文管理器的类型要求。
工具支持情况
- Pyright:完全支持PEP 612,无需额外配置。
- Mypy:从0.800版本开始支持,确保使用足够新的版本即可。
这种方式的核心优势是,原函数(比如os.open)的类型签名随版本更新时,包装器的类型会自动同步,无需手动修改标注。
内容的提问来源于stack exchange,提问作者nh2
相关产品推荐
相关产品推荐

