Python中如何在class里使用self的装饰器

原本想实现这样的功能

class a:
  logs=[]

@self.log() def b(): print(‘1’)

def log(self,text=’’): def decorator(func): @functools.wraps(func) def wrapper(s, *args, **kw): self.logs.append(func,args,kw) return func(*args, **kw) return wrapper

return decorator

def redo(self): for _ in self.logs: _0

但这是错误的,[@self](/user/self).log()会报错 NameError: name 'self' is not defined 也想过把 log 拉出来,不放在 class a 里,有 2 个思路: 1.log 加一个 object 的参数,每次把这个 class 传进去 2.log()用 class 包裹起来,先初始化把 class a 传进去,后来调用就不用加 object 的参数了。

但是遇到问题 思路 1:[@log](/user/log)(self)也是会报错 NameError: name 'self' is not defined 思路 2:没办法所有操作在 class a 内完成,没办法做成包调用

求助 QAQ


Python中如何在class里使用self的装饰器

20 回复

= =在线等!!


在Python类里用self当装饰器参数,关键得用__get__方法把装饰器变成描述符。直接传self会报错,因为定义时self还不存在。

看这个例子,我们做个记录方法调用次数的装饰器:

import functools

class call_counter:
    def __init__(self, func):
        functools.update_wrapper(self, func)
        self.func = func
        self.count = 0
    
    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"{self.func.__name__} called {self.count} times")
        return self.func(*args, **kwargs)
    
    def __get__(self, obj, objtype=None):
        # 这步是关键:把实例方法绑定到类实例
        if obj is None:
            return self
        return functools.partial(self.__call__, obj)

class MyClass:
    @call_counter
    def my_method(self):
        print("Method executed")
    
    @call_counter
    def another_method(self, x):
        return x * 2

# 使用示例
obj = MyClass()
obj.my_method()  # 输出: my_method called 1 times
obj.my_method()  # 输出: my_method called 2 times
obj.another_method(5)  # 输出: another_method called 1 times

核心是__get__方法:当装饰器被当作实例方法访问时,它返回一个绑定了实例的partial函数。这样调用时就能正确传递self参数了。

还有个更简洁的写法,用类装饰器:

class track_calls:
    def __init__(self, method):
        self.method = method
        self.count = 0
    
    def __get__(self, obj, objtype=None):
        def wrapper(*args, **kwargs):
            self.count += 1
            print(f"{self.method.__name__} called {self.count} times")
            return self.method(obj, *args, **kwargs)
        return wrapper

用描述符机制解决装饰器访问问题。

头上无数黑线飘过

为什么要这样写装饰器?


TAT 能说说?

log 定义成静态方法或者类方法,然后 @ a.log

#4 你为什么要把装饰器放类里面呀?放类外面不就完了。你调用装饰器的时候用 self 肯定不对啊。

这样?
![image]( )

#4 你如果想取对象里面的变量,也不是这样写的。这个各种教程里面有说,我就不说了。

因为我需要把数据放进 class a 里面去啊 QAQ
变成静态之后得把 a 对象传进去,跟我思路 1 一个问题。。

😃对的就是这个效果😭居然没想到,谢谢!

<br>import functools<br><br>def log():<br> def decorator(func):<br> .wraps(func)<br> def wrapper(self, *args, **kwargs):<br> self.logs.append([func, args, kwargs])<br> return func(self, *args, **kwargs)<br> return wrapper<br> return decorator<br><br>class a:<br> logs = []<br> <br> ()<br> def b(self, log):<br> print(1)<br><br><br>c = a()<br>c.b("ccc")<br>print(c.logs)<br>


不知道是不是你需要的结果。。self.logs.append(func,args,kw) 这里也是不对的,列表在进行 append 操作的时候只能添加一个。。



完。。。全错了

首先 python 装饰器是编译时执行的,而且 self 代表当前类的实例在调用类方法的时候作为第一个参数,self 只是一个约定成俗的写法

self 是在创建对象实例之后调用函数的时候才绑定的,所以在外面是不能用 self 的。改成静态函数,然后把 logs 属性按照类属性来用 a.logs.append 就可以。

哈哈跟#7 一样,谢谢回复
对,我知道。所以我没这样用。。。

懂的
😂这个问题的点不在这里,我的代码里已经解决了这个问题

回到顶部