【发布时间】:2010-10-14 13:15:09
【问题描述】:
我想按照以下原则构建用作装饰器的类:
- 应该可以在 1 个函数的顶部堆叠多个此类装饰器。
- 生成的函数名称指针应该与没有装饰器的同一个函数无法区分,可能只是因为它是哪个类型/类。
- 除非装饰器确实强制执行,否则取消装饰器的命令不应该是相关的。 IE。可以按任何顺序应用独立的装饰器。
这是一个 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));
此外,尝试在 NullDecl 构造函数中添加“print func.name”,它将适用于第一个装饰器,但不适用于第二个 - 因为 name 将丢失。
稍微提炼了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
【问题讨论】:
-
+1 因为我不确定为什么有人否决了这个问题。这是一个很好的问题:关于 SO 的大多数装饰器问题都不使用类作为装饰器。无论人们如何想到使用类而不是函数,这是一个有效的问题,并且可能完全适合用例。