首页 > 解决方案 > 在运行时装饰类方法

问题描述

我想装饰一个类方法,但是在运行时(我的意思是装饰器不需要在带有@符号的方法之前指定)

请参阅标准方法装饰器的此示例:

def method_decorator(func):
    def decorated(self, *args, **kwargs):
        print('decorator:', args, kwargs)
        return func(self,*args, **kwargs)
    return decorated

class Standard():
    @ method_decorator
    def decorated(self, *args, **kwargs):
        print('decorated: ', args, kwargs)

s = Standard()
s.decorated(1,2)

结果:

decorator: (1, 2) {}
decorated:  (1, 2) {}

所以我在运行时尝试了不同的方法:

class RunTime():
    def set_decorator_1(self, decorator):
        self.decorated = decorator(self.decorated)
    def set_decorator_2(self, decorator):
        RunTime.decorated = decorator(RunTime.decorated)
    def set_decorator_3(self, decorator):
        self.decorated = decorator(RunTime.decorated)
    def set_decorator_4(self, decorator):
        setattr(self, 'decorated', decorator(RunTime.decorated))
    def set_decorator_5(self, decorator):
        setattr(self, 'decorated', decorator(self.decorated))
    def decorated(self, *args, **kwargs):
        print('decorated: ', args, kwargs)

r = RunTime()
r.set_decorator_*(method_decorator)
r.decorated(1,2)

以下是输出:

  1. 装饰器没有正确装饰:
decorator: (2,) {}
decorated:  (1, 2) {}
  1. 按预期工作,但是当调用 set_decorator 时,所有的 RunTime 实例也都被装饰了,我想避免这种情况,因为我只想装饰单个实例的方法。
  2. 装修不好
decorator: (2,) {}
decorated:  (2,) {}
  1. 与 3 相同
  2. 与 1 相同

我还尝试了另一个装饰器,它运行良好(使用 set_decorator_1)但不允许我在其中访问 self:

def method_decorator_runtime(func):
    def decorated( *args, **kwargs):
        print('decorator: ', args, kwargs)
        return func( *args, **kwargs)
    return decorated

有谁知道在运行时装饰方法的正确方法,并且能够在装饰器中访问 self ?

标签: pythonclassmethodsdecorator

解决方案


我为您的问题找到的最接近的解决方案是使用带有参数的装饰器,您可以在其中传递装饰了其方法的对象的实例。

def method_decorator(self_eventually):
    def decorator(func):
        def decorated(*args, **kwargs):
            print('decorator:', repr(self_eventually), args, kwargs)
            return func(*args, **kwargs)
        return decorated
    return decorator

class RunTime():

    def set_decorator(self, decorator):
        self.decorated = decorator(self)(self.decorated)

    def decorated(self, *args, **kwargs):
        print('decorated:', repr(self), args, kwargs)

r = RunTime()
r.set_decorator(method_decorator)
r.decorated(1, 2)

推荐阅读