共计 2277 个字符,预计需要花费 6 分钟才能阅读完成。
在前面的课程中,我们已经学习了闭包的概念,并初步接触过装饰器。今天我们将更深入地探讨 Python 装饰器的工作原理、常见用途以及如何编写可复用的装饰器函数。
一、什么是装饰器
装饰器(Decorator)是 Python 中非常强大的语法糖,用于在不改变函数代码的情况下,为函数“增加新功能”。
从本质上看,装饰器是一个 返回函数的函数。
举个最基本的例子:
def my_decorator(func):
def wrapper():
print(" 函数执行前的操作 ")
func()
print(" 函数执行后的操作 ")
return wrapper
@my_decorator
def say_hello():
print("Hello, Python!")
say_hello()
输出结果为:
函数执行前的操作
Hello, Python!
函数执行后的操作
解释:
@my_decorator相当于执行say_hello = my_decorator(say_hello)- 即在函数调用前后自动添加了新逻辑,实现功能扩展。
二、带参数的装饰器
上例中,装饰器只适用于无参数函数。
如果目标函数需要传参,我们可以在 wrapper 内部增加 *args 和 **kwargs。
def logger(func):
def wrapper(*args, **kwargs):
print(f" 开始执行函数:{func.__name__}")
result = func(*args, **kwargs)
print(f" 函数 {func.__name__} 执行完毕 ")
return result
return wrapper
@logger
def add(a, b):
return a + b
print(add(5, 8))
输出结果为:
开始执行函数:add
函数 add 执行完毕
13
说明:
装饰器可以通用地包装各种函数,无论有无参数。
三、装饰器的嵌套使用
多个装饰器可以叠加使用,执行顺序是 从下往上(即最接近函数定义的先执行)。
def deco1(func):
def wrapper():
print(" 进入 deco1")
func()
print(" 退出 deco1")
return wrapper
def deco2(func):
def wrapper():
print(" 进入 deco2")
func()
print(" 退出 deco2")
return wrapper
@deco1
@deco2
def test():
print(" 函数体执行中 ")
test()
输出顺序:
进入 deco1
进入 deco2
函数体执行中
退出 deco2
退出 deco1
说明:
先应用 @deco2,再由 @deco1 包裹,这样执行时会形成函数调用栈的层层嵌套。
四、带参数的装饰器
有时候我们希望装饰器本身也能接收参数,例如设定日志级别或启用某种模式。
此时需要用到 三层嵌套 结构:
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(n):
print(f" 第 {i+1} 次执行 {func.__name__}")
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def greet():
print("Hello!")
greet()
结果:
第 1 次执行 greet
Hello!
第 2 次执行 greet
Hello!
第 3 次执行 greet
Hello!
解释:
@repeat(3) 实际上调用 repeat(3) 返回一个装饰器,然后用于修饰函数。
五、实战示例:性能监控装饰器
装饰器常被用于日志记录、性能检测、权限校验等场景。
下面编写一个统计函数执行时间的装饰器:
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 执行耗时:{end - start:.4f} 秒 ")
return result
return wrapper
@timer
def slow_operation():
time.sleep(1)
print(" 操作完成 ")
slow_operation()
输出示例:
操作完成
slow_operation 执行耗时:1.0012 秒
这种方法在调试或性能优化时非常有用。
六、使用 functools.wraps 保留函数元信息
如果不使用 functools.wraps,被装饰函数的元信息(如名称、文档字符串)会丢失。
from functools import wraps
def safe_wrapper(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(" 正在调用函数...")
return func(*args, **kwargs)
return wrapper
@safe_wrapper
def demo():
""" 演示函数 """
pass
print(demo.__name__) # demo
print(demo.__doc__) # 演示函数
说明:
@wraps(func) 可以保留原函数的元数据,这在调试和文档生成时尤为重要。
七、小结
装饰器是 Python 高级函数式编程的核心工具之一。
本节要点:
- 装饰器本质上是返回函数的高阶函数;
- 使用
@语法糖简化装饰过程; - 可以嵌套、带参数、甚至动态控制逻辑;
- 使用
functools.wraps保留函数元信息。
掌握装饰器后,你将能写出更加优雅、模块化和可复用的 Python 代码。