可在父类外部调用的Python装饰方法
假设我有一个类用作装饰器,如下所示:可在父类外部调用的Python装饰方法,python,decorator,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中的值与修饰后的函数体相关) A类: @特殊方法 def剂量测量(自身、数据、其他数据): #下面
class specialmethod:
def __init__(self,func):
self.func = func
def __call__(self,arg1,arg2):
print arg1,arg2
self.func(arg1,arg2)
但是被修饰的方法在另一个类中,该类也必须使用self
(self中的值与修饰后的函数体相关)
A类:
@特殊方法
def剂量测量(自身、数据、其他数据):
#下面这个家伙没有得到self的正确值,一个
打印类型(自身)
回溯(最近一次呼叫最后一次):
文件“deco.py”,第18行,在
a、 dosomething('foo','bar')
调用中第7行的文件“deco.py”__
self.func(arg1、arg2)
TypeError:dosomething()正好接受3个参数(给定2个)
如果没有装饰的话,self
的工作方式还有保留吗?我已经尝试显式地传递它,但它仍然需要错误数量的参数
编辑
我应该澄清,
dosomething
的最终函数体中self的预期值应该参考A
的实例。。。不希望将decorator实例放入修饰函数中。当您使用像decorator这样的类时,您必须意识到,将函数转换为方法(描述符协议,特别是\uuu get\uuuu
方法)的正常魔力对于您的类不起作用,除非您显式地实现它。您可以通过实现一个\uuuuu get\uuuuu
方法手动执行此操作,该方法返回一个新类型,该类型将记住从中检索到的实例以及要调用的实际可调用实例,但这需要大量的工作,但收获甚微
一种更常见的方法是不使用实际的类作为装饰器,而总是让装饰器返回实际的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
即使被修饰的函数是类中的方法,第一个方法仍然有效吗?这两个参数之前的附加
self
?如果要修饰的函数是类中的方法,则这两种方法都有效;在这两种情况下,arg1
是接收实例的参数,即包装函数中的self
。(我从您的示例中复制了命名,但通常您在包装器定义和对f
的调用中都使用*args,**kwargs
。在这种情况下,self
是args
元组中的第一项。)效果很好,谢谢!最后一个问题是,如果被修饰的方法是A
的神奇方法之一,比如\uuuuu调用\uuuuuuuu
,行为会有所不同吗?不,装饰器返回函数意味着结果是一个完全常规的Python版本,Python无法区分原始函数和修饰函数之间的区别。它的工作原理完全相同。为什么需要functools.wrapps?
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