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

如何批量装饰Python类方法?实现调用日志与耗时统计

类级方法调用日志与耗时统计装饰器实现

要实现给整个类的方法自动添加调用日志和耗时统计,且支持嵌套调用的缩进显示,可以通过类装饰器完成核心逻辑:遍历类的所有属性,将符合条件的实例方法替换为带计时和日志的包装函数,同时用线程局部变量跟踪调用深度,保证多线程场景下的缩进正确。

完整实现代码

import time
import inspect
import threading

def class_method_tracer(target_methods=None, exclude_special=True):
    """
    类装饰器:自动为类的实例方法添加调用日志与耗时统计
    :param target_methods: 指定要跟踪的方法名列表,None则跟踪所有实例方法
    :param exclude_special: 是否排除__开头的特殊方法,默认True
    """
    # 线程局部变量,用于跟踪每个线程的调用深度
    call_depth = threading.local()
    call_depth.value = 0

    def method_wrapper(func):
        def wrapped(*args, **kwargs):
            nonlocal call_depth
            # 增加调用深度
            call_depth.value += 1
            indent = "    " * (call_depth.value - 1)
            method_name = func.__name__
            
            # 打印调用日志
            print(f"{indent}调用方法\"{method_name}\"")
            
            # 计时并执行原方法
            start_time = time.perf_counter()
            result = func(*args, **kwargs)
            elapsed_time = time.perf_counter() - start_time
            
            # 打印耗时(这里简化为整数秒,实际可保留小数)
            print(f"{indent} 耗时{int(elapsed_time)}秒")
            
            # 减少调用深度
            call_depth.value -= 1
            return result
        return wrapped

    def class_decorator(cls):
        # 遍历类的所有属性
        for attr_name, attr_value in cls.__dict__.items():
            # 判断是否是实例方法
            if inspect.isfunction(attr_value):
                # 处理特殊方法排除
                if exclude_special and attr_name.startswith("__"):
                    continue
                # 处理指定方法过滤
                if target_methods and attr_name not in target_methods:
                    continue
                # 替换原方法为包装后的方法
                setattr(cls, attr_name, method_wrapper(attr_value))
        return cls

    return class_decorator

使用示例

@class_method_tracer()
class Adder:
    def add(self, a, b):
        # 模拟耗时,实际场景可移除
        time.sleep(1)
        return a + b

    def more_add(self, c, d):
        # 模拟耗时
        time.sleep(1)
        return self.add(self.add(c, d), self.add(c, d))

# 测试调用
Adder().add(1, 2)
print("---")
Adder().more_add(4, 5)

输出效果(与示例需求匹配)

调用方法"add"
 耗时1秒
---
调用方法"more_add"
    调用方法"add"
        调用方法"add"
          耗时1秒
        调用方法"add"
          耗时1秒
      耗时1秒
 耗时2秒

注:实际耗时会包含嵌套调用的总时间,示例数值为模拟效果,可根据需求调整计时逻辑。

关键细节说明

  • 线程安全:用threading.local()存储调用深度,避免多线程同时调用时缩进混乱
  • 灵活配置:可通过target_methods参数指定只跟踪特定方法,比如@class_method_tracer(target_methods=["add"])只会跟踪add方法
  • 特殊方法排除:默认排除__init__、__str__等特殊方法,避免日志混乱,可通过exclude_special=False关闭该功能
  • 无侵入性:不需要修改类内部的方法实现,也不需要继承,直接给类加装饰器即可

内容的提问来源于stack exchange,提问作者MaxTechniche

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:05:55