在 Python 的高级语法中,装饰器(Decorator) 是一个非常强大且常用的功能。它不仅能让代码更简洁,还能在不修改原有函数代码的前提下,为函数或类添加新的功能。无论是日志记录、性能监控、权限验证还是缓存机制,装饰器都能派上用场。
一、什么是装饰器
装饰器本质上是一个函数 ,它的作用是接收一个函数或类作为输入,并返回一个被增强后的新函数或类。
换句话说:
装饰器 = 高阶函数 + 闭包 的应用。
最简单的形式如下:
python
def decorator(func):
def wrapper():
print("函数执行前做一些准备工作...")
func()
print("函数执行后做一些收尾工作...")
return wrapper
@decorator
def hello():
print("Hello, Python!")
hello()
输出结果:
erlang
函数执行前做一些准备工作...
Hello, Python!
函数执行后做一些收尾工作...
当我们在 hello() 前加上 @decorator,相当于执行:
python
hello = decorator(hello)
这就是装饰器的核心原理。
二、装饰器的执行流程
我们用上面的例子来拆解执行过程:
- Python 解释器加载
hello()时,检测到@decorator - 执行
decorator(hello),并返回内部函数wrapper hello被替换成wrapper- 调用
hello()实际上执行的是wrapper()
通过这种方式,我们可以在函数执行的前后插入任意逻辑,而不必修改原函数体。
三、带参数的函数装饰器
如果被装饰的函数有参数怎么办? 没问题,只需让 wrapper 支持传入参数即可。
python
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(3, 5))
输出:
csharp
开始执行函数:add
函数 add 执行结束
8
四、带参数的装饰器(多层装饰)
有时候我们希望给装饰器本身传递参数,比如设置日志级别、权限名称等。
这就需要再包一层函数:
python
def log(level):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"[{level}] 开始执行 {func.__name__}")
result = func(*args, **kwargs)
print(f"[{level}] 执行结束 {func.__name__}")
return result
return wrapper
return decorator
@log("INFO")
def multiply(a, b):
return a * b
multiply(2, 4)
输出:
csharp
[INFO] 开始执行 multiply
[INFO] 执行结束 multiply
这里 @log("INFO") 实际上是执行了 log("INFO"),返回一个真正的装饰器函数。
五、同时使用多个装饰器
多个装饰器可以层层嵌套 ,执行顺序为自下而上。
python
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 hello():
print("Hello!")
hello()
执行结果:
进入 deco1
进入 deco2
Hello!
离开 deco2
离开 deco1
解释:hello = deco1(deco2(hello))
六、functools.wraps 的使用
一个常见问题是:装饰后的函数 __name__ 和 __doc__ 会被替换为 wrapper 的信息。
为了解决这个问题,Python 提供了 functools.wraps:
python
from functools import wraps
def logger(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"执行 {func.__name__}")
return func(*args, **kwargs)
return wrapper
@logger
def greet():
"""打印问候语"""
print("Hi there!")
print(greet.__name__) # greet
print(greet.__doc__) # 打印问候语
@wraps(func) 可以保留原函数的元信息,提升代码的可读性和可维护性。
七、类装饰器(进阶)
装饰器不仅可以是函数,也可以是类 。 只要类实现了 __call__() 方法,它就能像函数一样被调用。
python
class Timer:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
import time
start = time.time()
result = self.func(*args, **kwargs)
end = time.time()
print(f"{self.func.__name__} 执行耗时:{end - start:.4f} 秒")
return result
@Timer
def slow_task():
import time
time.sleep(1)
print("任务完成")
slow_task()
输出:
任务完成
slow_task 执行耗时:1.0001 秒
这种写法适合逻辑较复杂、需要保存状态的装饰场景。
八、总结
装饰器是 Python 的一项核心特性,能让代码结构更清晰、功能更模块化。 它的常见应用包括:
- 日志记录(logger)
- 性能监控(计时器)
- 权限验证(auth)
- 缓存机制(memoization)
- 接口规范化(API 装饰)
掌握装饰器后,你可以更优雅地编写出功能丰富且可扩展的 Python 程序。