我想构造用作装饰器的类,原则如下:
这是一个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 ”,它将适用于第一个装饰器,但不适用于第二个 - 因为名称将丢失。
精炼 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
答案 0 :(得分:23)
do-nothing装饰器类看起来像这样:
class NullDecl (object):
def __init__ (self, func):
self.func = func
for name in set(dir(func)) - set(dir(self)):
setattr(self, name, getattr(func, name))
def __call__ (self, *args):
return self.func (*args)
然后你可以正常应用它:
@NullDecl
def myFunc (x,y,z):
return (x+y)/z
答案 1 :(得分:10)
decorator module可以帮助您编写保留签名的装饰器。
PythonDecoratorLibrary可能会为装饰者提供有用的示例。
答案 2 :(得分:7)
要创建一个包装函数的装饰器,使其与原始函数无法区分,请使用functools.wraps
。
示例:
def mydecorator(func):
@functools.wraps(func):
def _mydecorator(*args, **kwargs):
do_something()
try:
return func(*args, **kwargs)
finally:
clean_up()
return _mydecorator
# ... and with parameters
def mydecorator(param1, param2):
def _mydecorator(func):
@functools.wraps(func)
def __mydecorator(*args, **kwargs):
do_something(param1, param2)
try:
return func(*args, **kwargs)
finally:
clean_up()
return __mydecorator
return _mydecorator
(我个人的偏好是使用函数创建装饰器,而不是类)
装饰器的顺序如下:
@d1
@d2
def func():
pass
# is equivalent to
def func():
pass
func = d1(d2(func))