Python装饰器触发Mypy 'Untyped'类型检查错误的解决方法
解决Mypy报"Untyped decorator makes function 'score' untyped"的问题
核心原因
Mypy无法识别装饰器的类型签名,尤其是装饰类方法时,若未正确标注装饰器的泛型类型以匹配原函数的参数(包括类实例self)和返回值,就会触发该错误。
修复方案
使用typing模块的ParamSpec和TypeVar来保留被装饰函数的完整类型信息,让Mypy能正确推断装饰后函数的类型。
1. 基础无参数装饰器示例
from typing import Callable, TypeVar, ParamSpec # 定义参数规范和返回值类型变量 P = ParamSpec("P") R = TypeVar("R") def process_without_columns(func: Callable[P, R]) -> Callable[P, R]: def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: # 这里写你的装饰器逻辑,比如移除columns参数 kwargs.pop("columns", None) return func(*args, **kwargs) return wrapper
2. 类方法中使用装饰器
class Scorer: @process_without_columns def score(self, data: dict, columns: list[str] | None = None) -> float: # 你的业务逻辑 return 0.5
3. 带参数的装饰器(如果需要)
如果你的装饰器需要接收额外参数,需嵌套一层并保持类型注解的一致性:
from typing import Callable, TypeVar, ParamSpec P = ParamSpec("P") R = TypeVar("R") def process_without_columns(exclude_cols: list[str]): def decorator(func: Callable[P, R]) -> Callable[P, R]: def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: # 根据传入的参数处理kwargs for col in exclude_cols: kwargs.pop(col, None) return func(*args, **kwargs) return wrapper return decorator # 使用示例 class Scorer: @process_without_columns(exclude_cols=["columns", "extra"]) def score(self, data: dict, columns: list[str] | None = None) -> float: return 0.5
关键注意事项
- 确保使用Python 3.10+或Mypy 0.910+,旧版本对
ParamSpec的支持不完善 - 装饰器的输入和输出必须严格匹配
Callable[P, R],保证类型信息不丢失 - 若装饰器修改了原函数的参数或返回值,需调整类型注解以匹配实际行为
内容的提问来源于stack exchange,提问作者Micah Pearce
相关产品推荐
相关产品推荐

