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>