Украшение методов класса Python - как передать экземпляр декоратору?
Это Python 2.5, и он GAE тоже, но это не так важно.
У меня есть следующий код. Я украшаю метод 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
в класс декоратора?
Ответы
Ответ 1
Вам нужно превратить декоратор в дескриптор - либо убедившись, что его (мета) класс имеет метод __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
по желанию.
Ответ 2
Алекс ответа достаточно, когда функции достаточно. Однако когда вам нужен класс, вы можете заставить его работать, добавив следующий метод в класс декоратора.
def __get__(self, obj, objtype):
"""Support instance methods."""
import functools
return functools.partial(self.__call__, obj)
Чтобы понять это, вам нужно понять протокол дескриптора. Протокол дескриптора - это механизм для привязки объекта к экземпляру. Он состоит из __ get __, __set __ и __ delete __, которые вызываются при получении, установке или удалении объекта из словаря экземпляров.
В этом случае, когда вещь получается из экземпляра, мы привязываем первый аргумент его метода __call__ к экземпляру, используя частичное. Это делается автоматически для функций-членов, когда класс создается, но для синтетической функции-члена, подобной этой, нам нужно сделать это явно.
Ответ 3
Декораторы могут быть немного сложными в Python. Вот пример того, что я когда-нибудь придумал. Вы могли бы сделать вывод о том, что вы пытаетесь сделать.
Проверка подлинности Django и Ajax - URL-адреса, требующие входа в систему
Ответ 4
Если вы хотите написать декоратор как класс, вы можете сделать:
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 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