Python中内置装饰器
Python 装饰器(Decorator)是一种强大的语法,用于在不修改原函数代码的前提下,动态地增强函数的功能。它本质上是一个高阶函数(接收函数作为参数,并返回一个新函数),通常用于日志记录、权限验证、缓存等场景。
一、装饰器的核心原理
装饰器的作用可以概括为:“包装”原函数,在原函数执行前后添加额外逻辑,同时不改变原函数的调用方式。
基本流程:
- 定义一个装饰器函数(接收被装饰的函数作为参数)
- 在装饰器内部定义一个“包装函数”(实现增强逻辑)
- 返回这个包装函数替换原函数
二、基础示例:最简单的装饰器
下面通过一个“计时装饰器”示例,理解装饰器的基本用法:
# 1. 定义装饰器:计算函数执行时间
def timer_decorator(func):# 3. 定义包装函数(包装原函数)def wrapper():import timestart = time.time() # 执行前:记录开始时间func() # 调用原函数end = time.time() # 执行后:记录结束时间print(f"函数执行耗时:{end - start:.2f}秒")# 4. 返回包装函数(替换原函数)return wrapper# 2. 使用装饰器:用@语法修饰目标函数
@timer_decorator
def slow_function():# 模拟耗时操作import timetime.sleep(1)print("函数执行完毕")# 调用被装饰后的函数(调用方式不变)
slow_function()
输出:
函数执行完毕
函数执行耗时:1.00秒
关键点:
@timer_decorator
等价于slow_function = timer_decorator(slow_function)
- 调用
slow_function()
时,实际执行的是装饰器返回的wrapper()
函数 - 原函数
slow_function
的功能被保留,同时新增了“计时”功能
三、带参数的函数如何装饰?
如果被装饰的函数有参数,需要在包装函数中传递参数:
def log_decorator(func):# 包装函数接收任意参数 *args 和 **kwargsdef wrapper(*args, **kwargs):print(f"调用函数:{func.__name__},参数:{args}, {kwargs}")result = func(*args, **kwargs) # 传递参数给原函数print(f"函数返回值:{result}")return result # 返回原函数的结果return wrapper@log_decorator
def add(a, b):return a + b# 调用带参数的函数
add(3, 5)
输出:
调用函数:add,参数:(3, 5), {}
函数返回值:8
说明:
*args
接收任意数量的位置参数(如3, 5
)**kwargs
接收任意数量的关键字参数(如a=3, b=5
)- 确保包装函数的参数能覆盖原函数的所有可能参数
四、带参数的装饰器
装饰器本身也可以接收参数,用于动态调整装饰逻辑。需要在原有装饰器外层再嵌套一层函数:
# 带参数的装饰器:允许指定日志前缀
def prefix_log_decorator(prefix):# 第一层:接收装饰器参数def decorator(func):# 第二层:接收被装饰函数def wrapper(*args, **kwargs):print(f"[{prefix}] 调用函数:{func.__name__}")return func(*args, **kwargs)return wrapperreturn decorator# 使用带参数的装饰器
@prefix_log_decorator(prefix="INFO")
def greet(name):return f"Hello, {name}!"greet("kk")
输出:
[INFO] 调用函数:greet
执行逻辑:
@prefix_log_decorator("INFO")
等价于:
greet = prefix_log_decorator("INFO")(greet)
下例可以验证上述执行逻辑:
def prefix_log_decorator(prefix):# 第一层:接收装饰器参数def decorator(func):# 第二层:接收被装饰函数def wrapper(*args, **kwargs):print(f"[{prefix}] 调用函数:{func.__name__}")return func(*args, **kwargs)return wrapperreturn decoratordef AaddB(a,b):print(a+b)prefix_log_decorator("INFO")(AaddB)(1,2)
五、保留原函数信息
装饰器会默认替换原函数的元信息(如 __name__
、__doc__
),可以用 functools.wraps
修复:
import functoolsdef my_decorator(func):@functools.wraps(func) # 保留原函数信息def wrapper(*args, **kwargs):return func(*args, **kwargs)return wrapper@my_decorator
def example():"""这是示例函数的文档字符串"""passprint(example.__name__) # 输出:example(而非 wrapper)
print(example.__doc__) # 输出:这是示例函数的文档字符串
六、常见应用场景
- 日志记录:自动记录函数调用信息、参数、返回值
- 权限验证:在函数执行前检查用户权限
- 缓存:缓存函数结果,避免重复计算
- 性能测试:统计函数执行时间
- 输入验证:检查函数参数是否符合要求
总结
- 装饰器是“包装函数”的工具,核心是不修改原函数代码却能增强其功能
- 基础语法:
@装饰器名
放在函数定义上方 - 处理参数:用
*args, **kwargs
适配任意参数的函数 - 带参数的装饰器:需要多一层函数嵌套
- 最佳实践:用
functools.wraps
保留原函数信息
装饰器是 Python 中“开闭原则”(对扩展开放,对修改关闭)的典型实现,在框架(如 Flask、Django)中被广泛使用。