代码之家  ›  专栏  ›  技术社区  ›  Staale

python中的decorator类

  •  37
  • Staale  · 技术社区  · 16 年前

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

    1. 应该可以将多个这样的类修饰符叠加到一个函数之上。
    2. 结果函数名指针应该与不带修饰符的同一个函数不可区分,请保存它的类型/类。
    3. 除非装饰师实际授权,否则订购装饰师不应相关。也就是说,独立的装饰师可以按任何顺序使用。

    这是针对一个Django项目的,我现在正在研究的具体情况是,该方法需要2个修饰器,并且要显示为一个普通的python函数:

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

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

    @accesscheck根据项目_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构造函数中,它将为第一个修饰器工作,但不会丢失第二个as名称。

    精炼的 爱德菲 回答有点问题,而且似乎效果很好:

    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 回复  |  直到 16 年前
        1
  •  22
  •   Staale    16 年前

    Do Nothing Decorator类如下所示:

    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
    
        2
  •  10
  •   f3lix    16 年前

    这个 decorator module 帮助您编写保留签名的装饰器。

    以及 PythonDecoratorLibrary 可能为装饰师提供有用的例子。

        3
  •  7
  •   codeape    16 年前

    要创建一个包装函数使其与原始函数不可区分的装饰器,请使用 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))