You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 16:20:11