装饰类方法——如何将实例传递给装饰器?

这是 Python 2.5,也是 GAE,不过没关系。

我有以下代码。我在 bar 中装饰 foo ()方法,使用 dec_check类作为装饰器。

class dec_check(object):


def __init__(self, f):
self.func = f


def __call__(self):
print 'In dec_check.__init__()'
self.func()


class bar(object):


@dec_check
def foo(self):
print 'In bar.foo()'


b = bar()
b.foo()

在执行这个命令时,我希望看到:

In dec_check.__init__()
In bar.foo()

但是我得到的 TypeError: foo() takes exactly 1 argument (0 given)作为 .foo(),作为一个对象方法,使用 self作为参数。我猜问题在于,当我执行装饰器代码时,bar的实例实际上并不存在。

那么如何将 bar的实例传递给装饰器类呢?

43135 次浏览

您需要将修饰符设置为 描述符——要么通过确保其(meta)类具有 __get__方法,要么通过使用修饰符 功能而不是修饰符 同学们(因为函数已经是描述符)使 方式更简单。例如:

def dec_check(f):
def deco(self):
print 'In deco'
f(self)
return deco


class bar(object):
@dec_check
def foo(self):
print 'in bar.foo'


b = bar()
b.foo()

这个指纹

In deco
in bar.foo

如你所愿。

当一个函数足够的时候 Alex 的答案就足够了。但是,当您需要一个类时,您可以通过将以下方法添加到装饰器类来使其工作。

def __get__(self, obj, objtype):
"""Support instance methods."""
import functools
return functools.partial(self.__call__, obj)

要理解这一点,您需要理解描述符协议。描述符协议是将事物绑定到实例的机制。它由 __get____set____delete__组成,当事物从实例字典中获取、设置或删除时调用它们。

在这种情况下,当从实例中获取内容时,我们使用局部方法将其 __call__方法的第一个参数绑定到实例。对于构造类时的成员函数,这是自动完成的,但是对于这样的合成成员函数,我们需要显式完成。

如果你想把装饰器写成一个类,你可以这样做:

from functools import update_wrapper, partial


class MyDecorator(object):
def __init__(self, func):
update_wrapper(self, func)
self.func = func


def __get__(self, obj, objtype):
"""Support instance methods."""
return partial(self.__call__, obj)


def __call__(self, obj, *args, **kwargs):
print('Logic here')
return self.func(obj, *args, **kwargs)


my_decorator = MyDecorator


class MyClass(object):
@my_decorator
def my_method(self):
pass