装饰python类的方法,我如何将实例传递给装饰器?
这是python2.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()
,作为一个对象的方法,把自己作为一个参数。 我猜测问题是,当我执行装饰器代码时, bar
的实例并不存在。
那么如何将一个实例传递给装饰类呢?
你需要通过确保它的(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 __组成,当事物从实例字典中被获取,设置或删除时被调用。 在这种情况下,当事件从实例中获得时,我们将它的第一个参数__调用__方法绑定到实例,使用partial。 这是在构造类时为成员函数自动完成的,但是对于像这样的合成成员函数,我们需要明确地做到这一点。
装饰器在Python中可能有点棘手。 这里有一个我曾经工作过的例子。 你可以从中推断出你正在做的事情。
Djangoauthentication和Ajax – 需要login的URL
如果你想写的装饰作为一个类,你可以做。
from functools import update_wrapper, partial MyDecorator(object): def __init__(self, func): update_wrapper(self, func) self.func = func def __get__(self, obj, objtype): """Support instance methods.""" return functools.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