Python中的Decorator类

Decorator classes in Python

我想构建一些类作为装饰器使用,它们的原则是完整的:

  • 应该可以将多个这样的类修饰符叠加到一个函数之上。
  • 结果函数名指针应该与不带修饰符的同一个函数不可区分,请保存它的类型/类。
  • 除非装饰师实际授权,否则订购装饰师不应相关。也就是说,独立的装饰师可以按任何顺序使用。
  • 这是针对一个Django项目的,我现在正在研究的具体情况是,该方法需要2个修饰器,并且要显示为一个普通的python函数:

    1
    2
    3
    @AccessCheck
    @AutoTemplate
    def view(request, item_id) {}

    @autotemplate更改了函数,因此它不返回httpresponse,而只返回一个字典用于上下文。使用了RequestContext,并从方法名和模块推断模板名。

    @accesscheck根据项目_id添加对用户的附加检查。

    我猜这只是为了让构造函数正确并复制适当的属性,但是这些属性是什么?

    下面的装饰器不能像我描述的那样工作:

    1
    2
    3
    4
    5
    class NullDecl (object):
        def __init__ (self, func):
            self.func = func
        def __call__ (self, * args):
            return self.func (*args)

    如以下代码所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @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",它将为第一个修饰器工作,但不会丢失第二个as名称。

    Eduffy的回答有点精练,而且似乎效果很好:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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


    Do Nothing Decorator类如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    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)

    然后您可以正常应用它:

    1
    2
    3
    @NullDecl
    def myFunc (x,y,z):
       return (x+y)/z


    decorator模块帮助您编写保留签名的decorator。

    而pythondecoratorlibrary可能为装饰师提供有用的例子。


    要创建一个包装函数使其与原始函数不可区分的装饰器,请使用functools.wraps

    例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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

    (我个人的偏好是使用函数而不是类创建装饰器)

    装饰师的订购如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @d1
    @d2
    def func():
        pass

    # is equivalent to
    def func():
        pass

    func = d1(d2(func))