【问题标题】:decorating decorators: try to get my head around understanding it装饰装饰器:试着让我的头脑理解它
【发布时间】:2011-08-22 14:21:17
【问题描述】:

我正在尝试了解如何装饰装饰器,并想尝试以下方法:

假设我有两个装饰器并将它们应用到函数hello()

def wrap(f):
    def wrapper():
        return " ".join(f())
    return wrapper


def upper(f):
    def uppercase(*args, **kargs):
        a,b = f(*args, **kargs)
        return a.upper(), b.upper()
    return uppercase

@wrap
@upper
def hello():
    return "hello","world"

print(hello())

然后我必须开始为其他功能添加其他装饰器,但通常@wrap 装饰器会“包装所有这些”

def lower(f):
    def lowercase(*args, **kargs):
        a,b = f(*args, **kargs)
        return a.lower(), b.lower()
    return lowercase

@wrap
@lower
def byebye():
    return "bye", "bye"

如何编写一个装饰器来装饰我的 @lower@upper 装饰器?见下文:

@wrap
def lower():
    ...

@wrap
def upper():
    ...

要达到与上述相同的结果,只需这样做:

@upper
def hello():
    ...

@lower
def byebye():
    ...

【问题讨论】:

标签: python decorator


【解决方案1】:
def upper(f):
    @wrap
    def uppercase(*args, **kargs):
        a,b = f(*args, **kargs)
        return a.upper(), b.upper()
    return uppercase

Python 中的装饰器

 @foo
 def bar(...): ...

就相当于

 def bar(...): ...
 bar = foo(bar)

你想要得到的效果

@wrap
@upper
def hello(): ....

hello = wrap(upper(hello))

所以应该在upper返回值上调用wrap

def upper_with_wrap(f):
   def uppercase(...): ...
   return wrap(uppercase)

这也相当于在该函数上应用装饰器:

def upper_with_wrap(f):
   @wrap
   def uppercase(...): ...
   # ^ equivalent to 'uppercase = wrap(uppercase)'
   return uppercase

【讨论】:

  • 这是一个不错的解决方案,但并不是我要问的,尽管也许我应该在问题中更清楚地说明它。尽管使用这种技术更简洁(也更容易理解),但我一直在研究如何显式地装饰装饰器。不过,您得到了我的支持,希望我能提供更多,特别是在解释您的答案所花费的时间:)
  • 正是我想要的!
【解决方案2】:

这是一个用装饰器装饰装饰器的通用解决方案(有点复杂)(耶!)。

# A second-order decorator
def decdec(inner_dec):
    def ddmain(outer_dec):
        def decwrapper(f):
            wrapped = inner_dec(outer_dec(f))
            def fwrapper(*args, **kwargs):
               return wrapped(*args, **kwargs)
            return fwrapper
        return decwrapper
    return ddmain

def wrap(f):
    def wrapper():
        return " ".join(f())
    return wrapper


# Decorate upper (a decorator) with wrap (another decorator)
@decdec(wrap)
def upper(f):
    def uppercase(*args, **kargs):
        a,b = f(*args, **kargs)
        return a.upper(), b.upper()
    return uppercase

@upper
def hello():
    return "hello","world"

print(hello())

【讨论】:

  • 这几乎回答了这个问题。你正在装饰一个装饰器,但我不是在寻找一个通用的解决方案,我实际上想要一个更简单的装饰器,因为无论我多久复习一次示例,我的头脑都必须绕过参数/作业:)跨度>
  • 好吧,你当然可以让它非泛型。甚至很简单:写mywrap = decdec(wrap),然后使用@mywrap 作为装饰器的装饰器。
猜你喜欢
  • 2017-03-01
  • 2011-09-03
  • 2015-11-18
  • 2017-08-20
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多