Python装饰器是一种用于修改或增强函数、类行为的设计模式,它可以在不修改原有代码的基础上,为函数或类添加额外的功能,是Python中实现功能增强的常用手段。

装饰器的基础原理
装饰器的本质是一个接收函数作为参数,并返回一个新函数的高阶函数。Python中通过@装饰器名的语法糖可以快速使用装饰器,其底层逻辑是将被装饰的函数作为参数传入装饰器,然后用装饰器返回的新函数替换原函数。
下面是一个最简单的无参装饰器示例,实现函数调用时的日志打印功能:
import functools
def log_decorator(func):
# 使用functools.wraps保留原函数的元信息
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"开始执行函数: {func.__name__}")
result = func(*args, **kwargs)
print(f"函数 {func.__name__} 执行完成")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
# 调用被装饰的函数
print(add(1, 2))
带参数的装饰器实现
如果需要给装饰器传递参数,就需要再嵌套一层函数,外层函数接收装饰器参数,中间层函数接收被装饰的函数,最内层是实际执行的逻辑函数。
以下是一个带参数的日志装饰器,可以自定义日志前缀:
import functools
def log_decorator_with_param(prefix=""):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"{prefix} 开始执行函数: {func.__name__}")
result = func(*args, **kwargs)
print(f"{prefix} 函数 {func.__name__} 执行完成")
return result
return wrapper
return decorator
@log_decorator_with_param(prefix="[DEBUG]")
def multiply(a, b):
return a * b
print(multiply(3, 4))
类装饰器的使用
除了函数形式的装饰器,还可以使用类实现装饰器,类装饰器需要实现__init__方法接收被装饰的函数,以及__call__方法实现调用逻辑。
下面是一个类装饰器示例,实现函数调用次数统计的功能增强:
import functools
class CallCountDecorator:
def __init__(self, func):
self.func = func
self.call_count = 0
functools.update_wrapper(self, func)
def __call__(self, *args, **kwargs):
self.call_count += 1
print(f"函数 {self.func.__name__} 已被调用 {self.call_count} 次")
return self.func(*args, **kwargs)
@CallCountDecorator
def greet(name):
return f"Hello, {name}"
print(greet("Alice"))
print(greet("Bob"))
常见功能增强场景示例
权限校验增强
在接口函数中添加权限校验逻辑,不需要修改每个接口的内部实现:
import functools
def auth_decorator(required_role):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 模拟当前用户角色获取
current_role = "admin"
if current_role != required_role:
raise PermissionError("无权限执行该操作")
return func(*args, **kwargs)
return wrapper
return decorator
@auth_decorator(required_role="admin")
def delete_user(user_id):
return f"删除用户 {user_id} 成功"
print(delete_user(1001))
性能统计增强
为函数添加执行时间统计的功能,方便排查性能问题:
import functools
import time
def time_stat_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"函数 {func.__name__} 执行耗时: {end_time - start_time:.4f} 秒")
return result
return wrapper
@time_stat_decorator
def heavy_compute():
total = 0
for i in range(1000000):
total += i
return total
print(heavy_compute())
使用装饰器的注意事项
- 使用
functools.wraps保留被装饰函数的元信息,避免函数名、文档字符串等属性丢失 - 装饰器的执行时机是在模块导入时,因此不要在装饰器中写过于耗时的初始化逻辑
- 多个装饰器装饰同一个函数时,执行顺序是从下往上,调用顺序是从上往下
- 如果装饰器需要处理被装饰函数的参数,要使用
*args和**kwargs保证参数传递的通用性