Python 应用于方法的可调用对象装饰器';无法在输入时获得自论证
结果:Python 应用于方法的可调用对象装饰器';无法在输入时获得自论证,python,functional-programming,parameter-passing,decorator,python-decorators,Python,Functional Programming,Parameter Passing,Decorator,Python Decorators,结果: import functools class Decor(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): def closure(*args, **kwargs): print args, kwargs return self.func(*args, **k
import functools
class Decor(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
def closure(*args, **kwargs):
print args, kwargs
return self.func(*args, **kwargs)
return closure(*args, **kwargs)
class Victim(object):
@Decor
def sum(self, a, b):
return a+b
v = Victim()
v.sum(1, 2)
Python函数充当,这意味着每当您访问类或实例上的函数时,都会调用它们的函数,并返回一个方法对象,该对象保留对原始函数的引用,对于实例,则保留对实例的引用。方法对象然后充当包装器;调用时,它们调用底层函数并将实例引用作为self
传递
另一方面,您的可调用类对象没有实现描述符协议,它没有。\uuuu get\uuuu()
方法,因此它从来没有机会绑定到实例。您必须自己实现此功能:
class Decor(object):
def __init__(self, func):
self.func = func
self.hooks = []
wraps(self.func)(self)
def __get__(self, instance, klass):
if instance != None: self.instance = instance
if klass != None: self.klass = klass
return self
def __call__(self, *args, **kwargs):
def closure(*args, **kwargs):
for function in self.hooks:
function(*args, **kwargs)
func = self.func
retval = func(*args, **kwargs) #kwargs_copy #called with notify = False
return retval
return closure.__get__(self.instance, self.klass)(*args, **kwargs)
演示:
并在您的装饰中使用它。\uuuu get\uuuu
,而不是生成一种方法:
>>> class Victim(object):
... @Decor
... def sum(self, a, b):
... return a+b
...
>>> v = Victim()
>>> v.sum
<bound method Victim.sum of <__main__.Victim object at 0x11013d850>>
>>> v.sum(1, 2)
<__main__.Victim object at 0x11013d850> (1, 2) {}
3
class DecorMethod(object):
def __init__(self, decor, instance):
self.decor = decor
self.instance = instance
def __call__(self, *args, **kw):
return self.decor(instance, *args, **kw)
def __getattr__(self, name):
return getattr(self.decor, name)
def __repr__(self):
return '<bound method {} of {}>'.format(self.decor, type(self))
这里的decormermethod
将对未知属性的任何请求传递回Decor
装饰器实例:
def __get__(self, instance, owner):
if instance is None:
return self
return DecorMethod(self, instance)
>类受害者(对象):
... @装饰
... 定义和(自身、a、b):
... 返回a+b
...
>>>v=受害者()
>>>v.sum
>>>v.sum.func
Easy way:让装饰器返回函数而不是类实例。不太简单的方法:实现,就像一个真正的函数一样。您将嵌套函数命名为\uuuu closure\uuuu
,但随后调用closure()
。那是错别字吗?哦,对不起,是错别字。我以前在测试时在控制台中修复了它,但忘记了修复它。谢谢你的明确解释。在发现您发布了答案之前,我在Python Decorator库中偶然发现了另一个示例:Martijn,您能建议一种方法使您的解决方案适应以下目标吗?我想在Decor
中存储一个钩子函数列表,并让Decor.\uuu调用\uuuu
在调用修饰函数之前调用每个钩子函数(例如受害者.sum
)。我需要在运行时更新钩子列表,方法是告诉受害者.sum.hooks.append(另一个函数)。同时,我需要能够将self
参数绑定到修饰函数(例如,Victor.sum
应该将Victor
实例作为self
参数)。有可能同时达到这两种能力吗?@Bob:那相当容易;我已经将实例
对象传递到调用
方法的装饰
对象更加明确;您可以在其中添加任意数量的额外函数,这些函数不必传递实例
,但您确实需要将其传递到修饰函数(self.func
)中。感谢您的回答,但按照您建议的方式,您不能说v.sum.hooks.append(另一个函数)
:v.sum
是一个绑定方法,由mfactory
生成,而不是Decor
可调用对象。它不允许访问装饰的属性。事实上,当我将Decor
制作成一个类而不是一个函数时,我的目的是将钩子存储在它的属性中。我想让\uuuu get\uuuu
返回Decor
实例本身,似乎我对您的答案(用它更新的问题)进行了修改。谢谢您可以访问类上的decorator(在这种特殊情况下,使用\uuuuu get\uuuu
方法)。
class DecorMethod(object):
def __init__(self, decor, instance):
self.decor = decor
self.instance = instance
def __call__(self, *args, **kw):
return self.decor(instance, *args, **kw)
def __getattr__(self, name):
return getattr(self.decor, name)
def __repr__(self):
return '<bound method {} of {}>'.format(self.decor, type(self))
def __get__(self, instance, owner):
if instance is None:
return self
return DecorMethod(self, instance)
>>> class Victim(object):
... @Decor
... def sum(self, a, b):
... return a + b
...
>>> v = Victim()
>>> v.sum
<bound method <__main__.Decor object at 0x102295390> of <class '__main__.DecorMethod'>>
>>> v.sum.func
<function sum at 0x102291848>