Python 装饰器介绍
·
装饰器是 Python 中用于修改函数 / 类行为的高阶函数,核心是通过包装目标对象,在不修改其源码的前提下增加额外功能(如日志、计时、权限校验等)。装饰器遵循 “开放封闭原则”,是 Python 进阶的核心特性之一。
一、装饰器核心原理
装饰器本质是:
- 定义一个接收函数 / 类作为参数的外层函数;
- 内层函数包装原函数的执行逻辑(前置 / 后置操作);
- 返回内层函数(替换原函数)。
核心语法:@装饰器名 是语法糖,等价于 原函数 = 装饰器名(原函数)。
二、装饰器分类与代码示例
1. 基础无参装饰器(最常用)
场景:给函数增加简单的额外功能(如日志、计时)。
示例 1:计时装饰器(统计函数执行时间)
import time
# 定义装饰器
def timer_decorator(func):
# 内层包装函数(*args, **kwargs 兼容任意参数)
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_decorator
def calculate_sum(n):
"""计算1到n的和"""
return sum(range(1, n+1))
# 调用测试
calculate_sum(1000000) # 输出:函数 calculate_sum 执行耗时:0.0200 秒(示例值)
示例 2:日志装饰器(记录函数调用信息)
def log_decorator(func):
def wrapper(*args, **kwargs):
# 前置操作:打印调用信息
print(f"[LOG] 函数 {func.__name__} 被调用,参数:args={args}, kwargs={kwargs}")
result = func(*args, **kwargs)
# 后置操作:打印返回值
print(f"[LOG] 函数 {func.__name__} 返回值:{result}")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
add(2, 3)
# 输出:
# [LOG] 函数 add 被调用,参数:args=(2, 3), kwargs={}
# [LOG] 函数 add 返回值:5
2. 带参数的装饰器
场景:装饰器需要自定义参数(如日志级别、超时时间)。原理:在基础装饰器外层再套一层函数,用于接收装饰器参数。
示例:带级别控制的日志装饰器
def log_decorator_with_level(level="INFO"):
# 外层:接收装饰器参数
def decorator(func):
# 中层:接收被装饰函数
def wrapper(*args, **kwargs):
# 内层:包装逻辑
print(f"[{level}] 函数 {func.__name__} 调用,参数:{args}")
result = func(*args, **kwargs)
return result
return wrapper
return decorator
# 使用装饰器(指定级别)
@log_decorator_with_level(level="DEBUG")
def multiply(a, b):
return a * b
# 不指定级别(使用默认值)
@log_decorator_with_level()
def subtract(a, b):
return a - b
multiply(4, 5) # 输出:[DEBUG] 函数 multiply 调用,参数:(4, 5)
subtract(10, 3) # 输出:[INFO] 函数 subtract 调用,参数:(10, 3)
3. 装饰类 / 类方法
示例 1:装饰类(给类增加属性 / 方法)
def add_prefix_decorator(prefix):
def decorator(cls):
# 给类的所有方法名加前缀
for attr in dir(cls):
if callable(getattr(cls, attr)) and not attr.startswith("__"):
original_method = getattr(cls, attr)
setattr(cls, f"{prefix}_{attr}", original_method)
return cls
return decorator
# 装饰类
@add_prefix_decorator("my")
class Calculator:
def add(self, a, b):
return a + b
# 使用
calc = Calculator()
print(calc.my_add(1, 2)) # 输出:3(调用装饰后新增的方法)
示例 2:装饰类方法 / 静态方法
def check_permission(func):
def wrapper(self, *args, **kwargs):
if self.user != "admin":
raise PermissionError("无权限")
return func(self, *args, **kwargs)
return wrapper
class AdminSystem:
def __init__(self, user):
self.user = user
@check_permission # 装饰实例方法
def delete_data(self):
print("数据删除成功")
@staticmethod
@log_decorator # 装饰静态方法(注意顺序:装饰器靠近方法)
def static_func():
print("静态方法执行")
# 测试
admin = AdminSystem("admin")
admin.delete_data() # 输出:数据删除成功
guest = AdminSystem("guest")
guest.delete_data() # 抛出 PermissionError
4. 保留原函数元信息(functools.wraps)
默认装饰器会丢失原函数的 __name__、__doc__ 等元信息,需用 functools.wraps 修复。
import functools
def decorator(func):
@functools.wraps(func) # 保留原函数元信息
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@decorator
def my_func():
"""这是原函数的文档字符串"""
pass
print(my_func.__name__) # 输出:my_func(未用wraps则输出wrapper)
print(my_func.__doc__) # 输出:这是原函数的文档字符串
5. 多个装饰器叠加
多个装饰器按自下而上的顺序执行(靠近函数的先执行)。
def decorator1(func):
def wrapper(*args, **kwargs):
print("装饰器1 前置")
result = func(*args, **kwargs)
print("装饰器1 后置")
return result
return wrapper
def decorator2(func):
def wrapper(*args, **kwargs):
print("装饰器2 前置")
result = func(*args, **kwargs)
print("装饰器2 后置")
return result
return wrapper
@decorator1
@decorator2
def test():
print("原函数执行")
test()
# 输出顺序:
# 装饰器1 前置
# 装饰器2 前置
# 原函数执行
# 装饰器2 后置
# 装饰器1 后置
三、装饰器常见应用场景
- 性能监控:统计函数执行时间、调用次数;
- 日志记录:记录函数调用参数、返回值、异常;
- 权限校验:接口 / 方法的访问权限控制;
- 缓存优化:缓存函数返回结果(如
lru_cache); - 参数校验:检查函数入参类型 / 范围;
- 重试机制:函数执行失败时自动重试。
四、内置装饰器
Python 提供了常用内置装饰器:
@property:将方法转为属性;@staticmethod:定义静态方法;@classmethod:定义类方法;@functools.lru_cache:缓存函数结果(优化重复计算)。
import functools
@functools.lru_cache(maxsize=None) # 无限制缓存
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
print(fib(100)) # 缓存后执行极快
总结
装饰器的核心是高阶函数 + 闭包,关键要点:
*args, **kwargs保证装饰器兼容任意参数;functools.wraps保留原函数元信息;- 带参装饰器需嵌套三层函数;
- 多个装饰器叠加时注意执行顺序;
- 可装饰函数、类、类方法等任意可调用对象。
装饰器是 Python 中 “优雅扩展功能” 的最佳实践,熟练掌握可大幅提升代码的简洁性和可维护性。
更多推荐


所有评论(0)