装饰员执行顺序

New*_*bie 72 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()
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

Mar*_*ers 97

装饰者包装他们正在装饰的功能.所以make_bold装饰了make_italic装饰器的结果,它装饰了这个hello功能.

@decorator语法真的只是语法糖; 下列:

@decorator
def decorated_function():
    # ...
Run Code Online (Sandbox Code Playgroud)

真的被执行为:

def decorated_function():
    # ...
decorated_function = decorator(decorated_function)
Run Code Online (Sandbox Code Playgroud)

用返回的内容替换原始decorated_function对象decorator().

堆叠装饰器重复向外处理.

所以你的样本:

@make_bold
@make_italic
def hello():
  return "hello world"
Run Code Online (Sandbox Code Playgroud)

可以扩展到:

def hello():
  return "hello world"
hello = make_bold(make_italic(hello))
Run Code Online (Sandbox Code Playgroud)

当你hello()现在打电话的时候,你正在调用返回的对象make_bold().make_bold()返回一个lambda调用函数make_boldwrapped,它是返回值make_italic(),也是一个调用原始函数的lambda hello().扩展所有这些来电:

hello() = lambda : "<b>" + fn() + "</b>" #  where fn() ->
    lambda : "<i>" + fn() + "</i>" # where fn() -> 
        return "hello world"
Run Code Online (Sandbox Code Playgroud)

所以输出变成:

"<b>" + ("<i>" + ("hello world") + "</i>") + "</b>"
Run Code Online (Sandbox Code Playgroud)

  • @Newbie:你的 IDE 在这里什么都不做;是 *Python* 进行包装。我在上一个示例中向您展示了 `make_bold()` 包装了 `make_italic()` 的输出,它用于包装 `hello`,因此相当于 `make_bold(make_italic(hello))`。 (3认同)

rka*_*ach 25

我认为这个问题的答案似乎很简单,但事实并非如此。当我们谈论装饰器的执行顺序时,我认为我们必须记住装饰器本身在执行过程中的不同时刻进行评估:当Python解释器评估装饰方法定义本身时以及调用/执行装饰方法时。正如我在实验中看到的,这两个阶段的装饰器顺序是不同的。

此外,请记住,在装饰函数时,我们可以让代码在被装饰的方法之前执行,并在之后运行。这使得嵌套装饰器时事情变得更加复杂。

所以,简而言之:

  • 当解释器评估装饰方法定义时,装饰器将从底部->顶部进行评估
  • 当解释器调用装饰方法时,装饰器将从top --> Bottom调用。

考虑以下代码示例:

print("========== Definition ==========")
def decorator(extra):
    print(" in decorator factory for %s " % extra)
    extra = " %s" % extra
    def inner(func):
        print(" defining decorator %s " % extra)
        def wrapper(*args, **kwargs):
            print("before %s -- %s" % (func.__name__, extra))
            func(*args, **kwargs)
            print("after %s -- %s" % (func.__name__, extra))
        return wrapper
    return inner

@decorator('first')
@decorator('middle')
@decorator('last')
def hello():
    print('  Hello ')

print("\n========== Execution ==========")
hello()
Run Code Online (Sandbox Code Playgroud)

该代码的输出如下:

========== Definition ==========
 in decorator factory for first 
 in decorator factory for middle 
 in decorator factory for last 
 defining decorator  last 
 defining decorator  middle 
 defining decorator  first 

========== Execution ==========
before wrapper --  first
before wrapper --  middle
before hello --  last
  Hello 
after hello --  last
after wrapper --  middle
after wrapper --  first
Run Code Online (Sandbox Code Playgroud)

正如我们在此输出中看到的,顺序是不同的(如前面所解释的)。在定义期间,装饰器从下到上评估,而在执行期间(通常是最重要的部分),它们从上到下评估。

回到问题中提出的示例,以下是示例代码(不使用 lambda):

print("========== Definition ==========")
def make_bold(fn):
    print("make_bold decorator")
    def wrapper():
        print("bold")
        return "<b>" + fn() + "</b>"
    return wrapper

def make_italic(fn):
    print("make_italic decorator")
    def wrapper():
        print("italic")
        return "<i>" + fn() + "</i>"
    return wrapper

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

print("\n========== Execution ==========")
print(hello())
Run Code Online (Sandbox Code Playgroud)

本例中的输出:

========== Definition ==========
make_italic decorator
make_bold decorator

========== Execution ==========
bold
italic
<b><i>hello world</i></b>
Run Code Online (Sandbox Code Playgroud)

新的执行顺序是从上到下。我们可以将相同的方法应用于原始代码(稍微修改一下以打印我们在哪里):

print("========== Definition ==========")

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

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

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

print("\n========== Execution ==========")
print(hello())
Run Code Online (Sandbox Code Playgroud)

输出是:

========== Definition ==========
make_italic
make_bold

========== Execution ==========
exec_bold
exec_italic
<b><i>hello world</i></b>
Run Code Online (Sandbox Code Playgroud)

我希望这能让您对 Python 中的装饰器顺序及其处理方式有所了解。