多个装饰器执行顺序的理解
@mirrornight 你跑下这段代码,看下输出?
#!/usr/bin/env python3
# coding: utf-8
import functools
def foo(func):
@functools.wraps(func)
def foo(*args, **kwargs):
print("foo")
func(*args, **kwargs)
return foo
def bar(func):
@functools.wraps(func)
def bar(*args, **kwargs):
print("bar")
func(*args, **kwargs)
return bar
@foo
@bar
def one():
raise Exception
r1 = one()
上面的代码的输出是:
foo
bar
Traceback (most recent call last):
File "./x.py", line 24, in <module>
r1 = one()
File "./x.py", line 9, in foo
func(*args, **kwargs)
File "./x.py", line 16, in bar
func(*args, **kwargs)
File "./x.py", line 22, in one
raise Exception
Exception
装饰器是由顶而下执行的。
感谢你抽空提出 PR,但是这个修改并不是正确的。
等等! import functools def foo(func): print('get in foo') @functools.wraps(func) def foo(*args, **kwargs): print("foo") func(*args, **kwargs) return foo
def bar(func): print('get in bar') @functools.wraps(func) def bar(*args, **kwargs): print("bar") func(*args, **kwargs) return bar
@foo @bar def one(): raise Exception
r1 = one()
输出: get in bar get in foo foo bar Traceback (most recent call last): ... raise Exception Exception
@mirrornight 从语法上看,你是对的。这里面其实有两组会被执行的“装饰器”,一种是装饰器函数自己,另一种是装饰器函数返回的函数。比如在下面这个例子里,
import functools
def foo(func):
print('get in foo')
@functools.wraps(func)
def _foo(*args, **kwargs):
print("foo")
func(*args, **kwargs)
return _foo
def bar(func):
print('get in bar')
@functools.wraps(func)
def _bar(*args, **kwargs):
print("bar")
func(*args, **kwargs)
return _bar
@foo
@bar
def one():
raise Exception
one()
foo 和 bar 会在解析 one 时执行,顺序是先 bar 后 foo。而 _foo 和 _bar 会在运行 one 时执行,顺序是先 _foo 后 _bar。
从上下文看,原作者描述的应该是类似于运行 one 的场景。不过这里的装饰器执行顺序的表达容易引起误会,也许应该改成“洋葱模型”这种表达?