问题: 装饰器执行的顺序是怎样的(先执行装饰器还是原函数)?

👇 点击展开/折叠 面试背诵模板(建议先背这个) 装饰器的执行顺序需分两个阶段理解:装饰阶段(定义时)从下往上执行装饰器工厂函数;调用阶段(运行时)从上往下执行包装函数。具体来说,@deco1 @deco2 def func() 中,装饰阶段先执行 deco2(靠近函数的先执行),再执行 deco1;调用 func() 时,先执行 deco1 的 wrapper 逻辑,再执行 deco2 的 wrapper 逻辑,最后执行原函数。
---

代码示例:装饰阶段顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def deco1(func):
print("1. 执行 deco1 装饰器")
def wrapper1():
print("3. 执行 wrapper1")
return func()
return wrapper1

def deco2(func):
print("2. 执行 deco2 装饰器")
def wrapper2():
print("4. 执行 wrapper2")
return func()
return wrapper2

@deco1 # 后执行
@deco2 # 先执行(靠近函数)
def target():
print("5. 执行原函数")

# 输出(装饰阶段):
# 2. 执行 deco2 装饰器
# 1. 执行 deco1 装饰器

target()
# 输出(调用阶段):
# 3. 执行 wrapper1
# 4. 执行 wrapper2
# 5. 执行原函数

执行顺序速览

阶段 顺序 说明
装饰阶段(定义时) 从下往上(靠近函数的先执行) 等价于 target = deco1(deco2(target))
调用阶段(执行时) 从上往下(最外层先执行) 先执行最外层装饰器的包装逻辑,逐层向内执行

本质解释

1
2
3
4
5
6
7
8
9
@deco1
@deco2
def target():
pass

# 完全等价于:
def target():
pass
target = deco1(deco2(target)) # 从右往左执行

实战对比:多个装饰器叠加时的注意事项

装饰器组合 定义时执行顺序 调用时执行顺序
@timer @logger def f(): logger 先执行,timer 后执行 timer 的 wrapper 先执行,logger 的 wrapper 后执行
装饰器 a 在最外层,b 在最内层 b 先执行,a 后执行 a 的 wrapper 先执行,b 的 wrapper 后执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from functools import wraps

def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("计时开始") # 先执行(最外层)
result = func(*args, **kwargs)
print("计时结束")
return result
return wrapper

def logger(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__}") # 后执行(内层)
return func(*args, **kwargs)
return wrapper

@timer
@logger
def process():
print("执行核心逻辑")

process()
# 输出顺序:
# 计时开始 ← timer 的 wrapper 先执行
# 调用 process ← logger 的 wrapper 后执行
# 执行核心逻辑 ← 原函数最后执行
# 计时结束

容易混淆的要点(面试高频)

  1. 装饰器本身在定义时执行,不是在调用时执行。
  2. 多个装饰器叠加:定义时从内向外(从下往上),调用时从外向内(从上往下)。
  3. **@deco1 @deco2 不等价于 @deco2 @deco1**,顺序交换会改变执行逻辑。