装饰的执行顺序

问题描述:

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,而不是相反。

那么这意味着它与大多数编程语言中的自顶向下方法的规范不同?只是为了装饰者的这种情况?或者我错了?

+2

是的,它从下往上传递结果到下一个 – 2014-12-07 11:28:37

装饰者包装他们装饰的功能。所以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包装,这是返回值make_italic(),这也是一个lambda,它调用原始hello()。展开所有这些调用你:

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

所以输出变成:

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

我的理解开始。但是这是否意味着在这种情况下有2个包装器时,IDE会自动检测并包装第一个包装器的结果?因为我认为'@make_bold #make_bold = make_bold(hello)' '@make_italiC#make_italic = make_italic(hello)'?我不确定是否基于此,它会包装第一个结果。或者对于这两个包装器的情况,IDE将使用'make_bold(make_italic(hello))'来代替我分享的内容。 – Newbie 2014-12-07 11:38:03

+0

@Newbie:你的IDE在这里什么也不做;它是* Python *的包装。我在最后一个示例中展示了make_bold()包装'make_italic()'的输出,该输出用于包装'hello',所以相当于'make_bold(make_italic(hello))'。 – 2014-12-07 11:40:41

+0

您能否提供此代码的版本而不使用lambda?我曾尝试.format但不起作用。为什么在这个例子中使用lambda?我试图理解lambda以及它在这个例子中是如何工作的,但仍然有问题。我得到的lambda就像一行函数,与def函数的规范相比,它可以很容易地传递? – Newbie 2014-12-07 12:20:38