Я хочу создать классы для использования в качестве декораторов с соблюдением следующих принципов:
- Должно быть возможно сложить несколько таких декораторов классов в функцию top-1.
- Полученный указатель имени функции должен быть неотличим от той же самой функции без декоратора, за исключением, возможно, только того, какой это тип / класс.
- Заказ декораторов не должен иметь отношения к делу, если это не было на самом деле санкционировано декораторами. То есть. независимые декораторы могут применяться в любом порядке.
Это для проекта Django, и в конкретном случае, над которым я сейчас работаю, метод требует 2 декоратора, и для его отображения в виде обычной функции python:
@AccessCheck
@AutoTemplate
def view(request, item_id) {}
@ AutoTemplate изменяет функцию так, что вместо возврата HttpResponse он просто возвращает словарь для использования в контексте. Используется RequestContext, а имя шаблона выводится из имени метода и модуля.
@ AccessCheck добавляет дополнительные проверки пользователя на основе item_id.
Я предполагаю, что это просто для правильного конструктора и копирования соответствующих атрибутов, но какие это атрибуты?
Следующий декоратор не будет работать, как я описываю:
class NullDecl (object):
def __init__ (self, func):
self.func = func
def __call__ (self, * args):
return self.func (*args)
Как показывает следующий код:
@NullDecl
@NullDecl
def decorated():
pass
def pure():
pass
# results in set(['func_closure', 'func_dict', '__get__', 'func_name',
# 'func_defaults', '__name__', 'func_code', 'func_doc', 'func_globals'])
print set(dir(pure)) - set(dir(decorated));
Кроме того, попробуйте добавить «print func. name » в конструктор NullDecl, и он будет работать для первого декоратора, но не для второго - так как имя будет отсутствовать.
Уточненный eduffy ответ немного, и, кажется, работает довольно хорошо:
class NullDecl (object):
def __init__ (self, func):
self.func = func
for n in set(dir(func)) - set(dir(self)):
setattr(self, n, getattr(func, n))
def __call__ (self, * args):
return self.func (*args)
def __repr__(self):
return self.func