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

Python中如何为类的不同实例创建独立的装饰器类实例?

问题解答

这个需求完全可以实现。

问题根因

你当前的写法存在两个核心问题:

  1. 类装饰器装饰类内方法时,装饰动作在waiter类定义阶段就完成了,全局只会生成1个decorater实例,所有waiter类的实例共享这一个装饰器实例,所以调用计数是全局累加的,无法按实例独立统计。
  2. 实例方法wait_for没有声明self参数,属于语法不规范,当前能跑通是因为装饰器在调用原方法时没有传入实例本身,属于巧合运行。

解决方案

我们可以让装饰器类实现Python的描述符协议,在方法绑定到实例时,为每个实例单独生成一个装饰器实例,把计数存在各自的装饰器实例中即可。

from functools import update_wrapper
import time

class decorater():
    """
    counts the number of calls and passes it into function
    """
    def __init__(self, func):
        self.func = func
        update_wrapper(self, func)

    def __get__(self, instance, owner):
        # 方法绑定到实例时,为当前实例生成专属的装饰器实例
        if instance is None:
            return self
        bound_decorator = decorater(self.func.__get__(instance, owner))
        # 把装饰器实例存到实例属性上,避免重复生成
        setattr(instance, self.func.__name__, bound_decorator)
        return bound_decorator

    def __call__(self, *args, **kwargs):
        if not hasattr(self, 'num_calls'):
            self.num_calls = 0
        self.num_calls += 1
        # 直接调用绑定后的方法,不需要额外传实例
        result = self.func(self.num_calls, *args, **kwargs)
        print(f"total runs of {self.func.__name__}: {self.num_calls}")
        return result
    
class waiter():
    """
    waits for the number of seconds passed in
    """
    @decorater
    def wait_for(self, seconds, var_name):
        time.sleep(seconds)
        print(f"{var_name} waited for {seconds} seconds")

waiter1 = waiter()
waiter2 = waiter()

waiter1.wait_for("waiter1")
waiter2.wait_for("waiter2")

运行结果

waiter1 waited for 1 seconds
total runs of wait_for: 1
waiter2 waited for 1 seconds
total runs of wait_for: 1

完全符合期望输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 21:45:03