2026-10-24 11:42:20
Python装饰器是一种强大的工具,通过“包裹”函数为其添加额外功能,而无需修改原函数代码。其核心原理基于函数是一等公民和闭包特性,利用@语法糖简化调用流程。以下是详细实现方法与原理分析:
一、基础装饰器实现核心结构:外部函数接收被装饰函数,返回嵌套的wrapper函数,wrapper执行额外逻辑并调用原函数。
import functoolsdef log_calls(func): @functools.wraps(func) # 保留原函数元信息 def wrapper(*args, kwargs): print(f"调用函数: {func.__name__},参数: {args}, {kwargs}") result = func(*args, kwargs) print(f"函数 {func.__name__} 返回: {result}") return result return wrapper@log_callsdef add(a, b): return a + b执行流程:
场景:需动态配置装饰器行为(如日志级别、计时单位)。实现方法:外层函数接收参数,返回真正的装饰器函数。
import timeimport functoolsdef timer(unit="seconds"): def decorator(func): @functools.wraps(func) def wrapper(*args, kwargs): start = time.perf_counter() result = func(*args, kwargs) duration = time.perf_counter() - start if unit == "milliseconds": duration *= 1000 unit_str = "ms" else: unit_str = "s" print(f"耗时: {duration:.4f} {unit_str}") return result return wrapper return decorator@timer(unit="milliseconds")def complex_calc(n): return sum(i*i for i in range(n))执行流程:
适用场景:需维护状态或共享资源(如调用次数统计、连接池管理)。核心要求:类实现__call__方法,使实例可调用。
import functoolsclass CallCounter: def __init__(self, func): functools.update_wrapper(self, func) # 保留元信息 self.func = func self.count = 0 def __call__(self, *args, kwargs): self.count += 1 print(f"{self.func.__name__} 调用次数: {self.count}") return self.func(*args, kwargs)@CallCounterdef greet(name): return f"Hello, {name}!"执行流程:
闭包机制:
wrapper函数捕获外部函数的变量(如func),即使外部函数已执行完毕,仍能通过闭包访问这些变量。
示例:log_calls中的wrapper通过闭包记住func,实现不修改原函数的情况下扩展行为。
functools.wraps的作用:
保留原函数的__name__、__doc__等元信息,避免装饰后函数显示为wrapper。
对比:无@functools.wraps时,add.__name__会返回"wrapper"。
装饰器执行顺序:
多个装饰器按从下到上的顺序应用(如@dec1 @dec2 func等价于dec1(dec2(func)))。
权限验证:
def require_auth(role): def decorator(func): @functools.wraps(func) def wrapper(user, *args, kwargs): if user.role != role: raise PermissionError("无权访问") return func(user, *args, kwargs) return wrapper return decorator@require_auth("admin")def delete_data(user): print("数据已删除")缓存装饰器:
def cache(func): cache_dict = {} @functools.wraps(func) def wrapper(*args): if args not in cache_dict: cache_dict[args] = func(*args) return cache_dict[args] return wrapperPython装饰器通过函数嵌套和闭包实现行为扩展,其核心优势在于不修改原函数代码即可添加功能。根据需求选择函数装饰器(简单逻辑)或类装饰器(状态管理),并善用functools.wraps保留元信息。理解闭包与一等函数特性后,可灵活实现日志、计时、权限控制等横切关注点。