如何让装饰器不覆盖原函数的类型提示?
解决装饰器覆盖原函数类型提示的问题
你的问题出在装饰器的类型注解太泛化——当前装饰器返回的是通用的Callable,导致原函数的参数名称、类型和返回类型信息都被覆盖了,调用时只能看到(...) -> Any的模糊提示。要让被装饰后的函数保留原函数的完整类型提示,可以用泛型类型注解来定义装饰器,具体实现如下:
修改后的代码
from typing import Callable, ParamSpec, TypeVar import functools # 定义泛型参数,捕获原函数的参数规格和返回类型 P = ParamSpec("P") R = TypeVar("R") def decorator(fn: Callable[P, R]) -> Callable[P, R]: # 使用functools.wraps继承原函数的元数据(非类型提示必需,但能提升使用体验) @functools.wraps(fn) def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: return fn(*args, **kwargs) return wrapper @decorator def foo_with_decorator(x: int, y: int) -> float: return x + y / 2 def foo(x: int, y: int) -> float: return x + y / 2 foo_with_decorator(10, 5) # 现在会显示完整类型提示:(x: int, y: int) -> float foo(10, 5) # (x: int, y: int) -> float
关键说明
ParamSpec("P"):专门用来捕获函数的参数规格(包含位置参数、关键字参数的类型和名称信息)TypeVar("R"):用来捕获原函数的返回类型- 装饰器的类型注解
Callable[P, R]明确了:输入一个参数规格为P、返回类型为R的函数,输出一个完全相同参数和返回类型的函数,这样类型检查工具就能保留原函数的所有类型提示 functools.wraps(fn):虽然不直接影响类型提示,但它会让装饰后的函数继承原函数的函数名、文档字符串等元数据,让调试和调用更贴近原函数的体验
内容的提问来源于stack exchange,提问作者user16965639
相关产品推荐
相关产品推荐

