Python使用可调用的外部父类装饰方法

时间:2012-02-08 18:39:06

标签: python decorator

让我们假设我有一个类用作装饰器,如:

class specialmethod:
  def __init__(self,func):
     self.func = func

  def __call__(self,arg1,arg2):
     print arg1,arg2
     self.func(arg1,arg2)

但是正在装饰的方法在另一个类中,也必须使用self(self中的值与后装饰时的函数体相关)

class A:
  @specialmethod
  def dosomething(self,data,otherdata):
    #this guy down here isn't getting the right value for self, an instance of A
    print type(self)

Traceback (most recent call last):
  File "deco.py", line 18, in <module>
    a.dosomething('foo','bar')
  File "deco.py", line 7, in __call__
    self.func(arg1,arg2)
TypeError: dosomething() takes exactly 3 arguments (2 given)

是否有保留self未装饰的方式?我已经尝试过明确地传递它,但它仍然需要错误的参数数量。

修改

我应该澄清,dosomething的最终函数体中self的预期值应该引用A的实例...而不是将装饰器实例放入装饰函数中。< / p>

1 个答案:

答案 0 :(得分:4)

当你使用类似装饰器的类时,你必须意识到将函数转换为方法的常规魔法(描述符协议,特别是__get__方法)不会为你的班级工作,除非你明确地实现它。您可以通过实现__get__方法来手动执行此操作,该方法返回一个新类型,该方法可以记住从中检索的实例以及要调用的实际可调用对象,但它的工作量非常大,只需要很少的收益

更常见的方法是不使用实际的类作为装饰器,并且总是让装饰器返回实际的Python函数。在这种特殊情况下,完全没有必要保留课程,所以你可以这样做:

def specialmethod(f):
    @functools.wraps(f)
    def wrapper(arg1, arg2):
        print arg1, arg2
        f(arg1, arg2)
    return wrapper

...但是如果你真的想保留课程,可以通过以下方式完成:

class _specialmethod:
  def __init__(self,func):
     self.func = func

  def __call__(self,arg1,arg2):
     print arg1,arg2
     self.func(arg1,arg2)

def specialmethod(f):
    wrapper_class = _specialmethod(f)
    @functools.wraps(f)
    def wrapper(arg1, arg2):
        wrapper_class(arg1, arg2)
    return wrapper