Python中的Decorator类

时间:2009-03-20 13:48:00

标签: python decorator

我想构造用作装饰器的类,原则如下:

  1. 应该可以在top off 1函数上堆叠多个这样的类装饰器。
  2. 生成的函数名称指针应该与没有装饰器的同一函数无法区分,可以保存它的类型/类。
  3. 除非装饰者实际要求,否则对装饰者进行排序不应该是相关的。 IE浏览器。独立装饰者可以按任何顺序应用。
  4. 这是一个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
    

3 个答案:

答案 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))