装饰员执行顺序

时间:2014-12-07 11:24:50

标签: python decorator python-decorators

def make_bold(fn):
    return lambda : "<b>" + fn() + "</b>"

def make_italic(fn):
    return lambda : "<i>" + fn() + "</i>"

@make_bold
@make_italic
def hello():
  return "hello world"

helloHTML = hello()

输出:"<b><i>hello world</i></b>"

我大致了解装饰器以及它在大多数示例中如何与其中一个一起工作。

在这个例子中,有2个。从输出中,@make_italic首先执行,然后@make_bold

这是否意味着对于装饰函数,它首先运行函数然后移动到其他装饰器的顶部?首先是@make_italic,然后是@make_bold,而不是相反的。

所以这意味着它与大多数编程语言中自上而下方法的规范不同?只为这个装饰器的情况?还是我错了?

1 个答案:

答案 0 :(得分:89)

装饰者包装他们正在装饰的功能。因此make_bold修饰了装饰make_italic函数的hello装饰器的结果。

@decorator语法实际上只是语法糖;以下内容:

@decorator
def decorated_function():
    # ...

实际执行为:

def decorated_function():
    # ...
decorated_function = decorator(decorated_function)

将原始decorated_function对象替换为返回的decorator()

堆叠装饰器重复该过程向外

所以你的样本:

@make_bold
@make_italic
def hello():
  return "hello world"

可以扩展为:

def hello():
  return "hello world"
hello = make_bold(make_italic(hello))

现在调用hello()时,您正在调用make_bold()返回的对象。 make_bold()返回了一个lambda,它调用函数make_bold wrap,这是make_italic()的返回值,它也是一个调用原始hello()的lambda。扩展所有这些来电:

hello() = lambda : "<b>" + fn() + "</b>" #  where fn() ->
    lambda : "<i>" + fn() + "</i>" # where fn() -> 
        return "hello world"

所以输出变为:

"<b>" + ("<i>" + ("hello world") + "</i>") + "</b>"