让我们假设我有一个类用作装饰器,如:
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>
答案 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