为staticmethod/classmethod装饰器添加mypy类型注解的问题
问题描述
我正在为日志库编写一个带跟踪(调试)日志功能的装饰器辅助工具,代码逻辑本身正确(部分基于现有库),但无法通过mypy的类型检查。以下是存在类型问题的代码(标注???的位置为类型存疑处),同时附上已实现正确类型注解的普通函数装饰器,以及修正后的staticmethod装饰器代码:
存在类型问题的staticmethod装饰器
def trace_static_method(_staticmethod: staticmethod) -> staticmethod: @wraps(_staticmethod.__func__) # 此处触发mypy类型错误 def wrapper(*args: ???, **kwargs: ???) -> ???: return _log_trace(_staticmethod.__func__, *args, **kwargs) return staticmethod(wrapper) # 此处触发mypy类型错误
存在类型问题的classmethod装饰器
def trace_class_method(_classmethod: classmethod) -> classmethod: @wraps(_classmethod.__func__) # 此处触发mypy类型错误 def wrapper(_cls: ???, *args: ???, **kwargs: ???) -> ???: method = _classmethod.__get__(None, _cls) # 此处触发mypy类型错误 return _log_trace(method, *args, **kwargs) return classmethod(wrapper) # 此处触发mypy类型错误
日志跟踪函数
from typing import Callable, ParamSpec, TypeVar P = ParamSpec("P") T = TypeVar("T") def _log_trace(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: name = func.__qualname__ module = func.__module__ logger_ = logger.opt(depth=1) logger_.log("TRACE", "{}.{} CALL args={}, kwargs={}", module, name, args, kwargs) result = func(*args, **kwargs) logger_.log("TRACE", "{}.{} RETURN {}", module, name, result) return result
已实现正确类型注解的普通函数装饰器
def trace(func: Callable[P, T]) -> Callable[P, T]: @wraps(func) def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: return _log_trace(func, *args, **kwargs) return wrapper
修正后的staticmethod装饰器
def trace_static_method(_staticmethod: staticmethod[P, T]) -> staticmethod[P, T]: @wraps(_staticmethod.__func__) def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: return _log_trace(_staticmethod.__func__, *args, **kwargs) return staticmethod(wrapper)
补充:修正后的classmethod装饰器
针对classmethod的类型问题,同样可以利用泛型参数完成类型注解,修正后的代码如下:
def trace_class_method(_classmethod: classmethod[P, T]) -> classmethod[P, T]: @wraps(_classmethod.__func__) def wrapper(_cls: type, *args: P.args, **kwargs: P.kwargs) -> T: method = _classmethod.__get__(None, _cls) return _log_trace(method, *args, **kwargs) return classmethod(wrapper)
关键说明
- Python 3.9+版本开始,
staticmethod和classmethod支持泛型参数(旧版本可通过typing_extensions库兼容),通过staticmethod[P, T]和classmethod[P, T]可以明确标注其内部函数的参数签名与返回值类型。 ParamSpec(P)用于捕获原函数的完整参数结构,TypeVar(T)用于绑定返回值类型,确保装饰器不会破坏原函数的类型信息,让mypy能够正确识别类型兼容性。
内容的提问来源于stack exchange,提问作者UnstableFractal
相关产品推荐
相关产品推荐

