Python装饰器:原理、应用与高级技巧

📅 2026/7/19 4:02:00
Python装饰器:原理、应用与高级技巧
1. Python装饰器基础概念装饰器(Decorator)是Python中一种强大的语法特性它允许我们在不修改原始函数代码的情况下动态地扩展函数的功能。装饰器本质上是一个高阶函数它接收一个函数作为参数并返回一个新的函数。1.1 为什么需要装饰器想象你正在开发一个Web应用有多个视图函数需要添加相同的功能比如记录函数执行日志检查用户权限计算函数执行时间缓存函数结果传统做法是在每个函数内部添加这些代码但这会导致大量重复代码。装饰器提供了一种优雅的解决方案让我们可以把这些横切关注点从业务逻辑中分离出来。1.2 装饰器的基本结构一个最简单的装饰器实现如下def my_decorator(func): def wrapper(): print(在函数执行前做一些操作) func() print(在函数执行后做一些操作) return wrapper my_decorator def say_hello(): print(Hello!)当调用say_hello()时实际上执行的是被装饰器包装后的wrapper函数输出结果为在函数执行前做一些操作 Hello! 在函数执行后做一些操作2. 装饰器的核心原理2.1 Python的函数特性理解装饰器需要先掌握Python函数的几个重要特性函数是一等对象可以像普通变量一样被赋值、传递def greet(name): return fHello, {name} hello greet # 将函数赋值给变量 print(hello(World)) # 输出: Hello, World函数可以嵌套定义def outer(): print(外部函数) def inner(): print(内部函数) inner() outer()函数可以作为返回值def create_greeter(greeting): def greeter(name): return f{greeting}, {name} return greeter say_hi create_greeter(Hi) print(say_hi(Alice)) # 输出: Hi, Alice2.2 装饰器的工作机制装饰器语法decorator实际上是一种语法糖它等价于def original_func(): pass original_func decorator(original_func)装饰器执行流程解释器遇到decorator时会立即执行decorator函数decorator函数接收被装饰的函数作为参数decorator返回一个新的函数通常是内部定义的wrapper函数原始函数名现在指向装饰器返回的新函数3. 装饰器的进阶用法3.1 装饰带参数的函数为了使装饰器能处理带参数的函数我们需要在wrapper函数中使用*args和**kwargsdef log_execution(func): def wrapper(*args, **kwargs): print(f准备执行: {func.__name__}) result func(*args, **kwargs) print(f执行完成: {func.__name__}) return result return wrapper log_execution def add(a, b): return a b print(add(3, 5))3.2 带参数的装饰器有时我们需要装饰器本身也能接收参数这需要再嵌套一层函数def repeat(num_times): def decorator(func): def wrapper(*args, **kwargs): for _ in range(num_times): result func(*args, **kwargs) return result return wrapper return decorator repeat(num_times3) def greet(name): print(fHello, {name}) greet(Alice)3.3 保留函数元信息使用装饰器后函数的__name__、__doc__等元信息会被wrapper函数覆盖。使用functools.wraps可以解决这个问题from functools import wraps def timing(func): wraps(func) def wrapper(*args, **kwargs): start time.time() result func(*args, **kwargs) end time.time() print(f{func.__name__}执行耗时: {end-start:.4f}秒) return result return wrapper4. 装饰器的实际应用场景4.1 性能测试import time from functools import wraps def timing(func): wraps(func) def wrapper(*args, **kwargs): start time.perf_counter() result func(*args, **kwargs) end time.perf_counter() print(f{func.__name__}耗时: {end-start:.6f}秒) return result return wrapper timing def slow_function(): time.sleep(1) slow_function()4.2 权限验证def requires_auth(func): wraps(func) def wrapper(*args, **kwargs): if not current_user.is_authenticated: raise PermissionError(需要登录) return func(*args, **kwargs) return wrapper requires_auth def view_profile(user_id): # 查看用户资料的逻辑 pass4.3 缓存结果from functools import lru_cache lru_cache(maxsize128) def fibonacci(n): if n 2: return n return fibonacci(n-1) fibonacci(n-2)4.4 日志记录import logging logging.basicConfig(levellogging.INFO) def log_call(func): wraps(func) def wrapper(*args, **kwargs): logging.info(f调用 {func.__name__} 参数: {args}, {kwargs}) try: result func(*args, **kwargs) logging.info(f{func.__name__} 返回: {result}) return result except Exception as e: logging.error(f{func.__name__} 出错: {str(e)}) raise return wrapper5. 类装饰器除了函数装饰器Python还支持类装饰器。类装饰器通过实现__call__方法来工作class CountCalls: def __init__(self, func): self.func func self.num_calls 0 wraps(func)(self) # 保持函数元信息 def __call__(self, *args, **kwargs): self.num_calls 1 print(f调用次数: {self.num_calls}) return self.func(*args, **kwargs) CountCalls def say_hello(): print(Hello!) say_hello() say_hello()6. 装饰器的高级技巧6.1 多个装饰器的执行顺序当多个装饰器应用于同一个函数时它们的执行顺序是从下往上decorator1 decorator2 decorator3 def func(): pass # 等价于 func decorator1(decorator2(decorator3(func)))6.2 装饰器工厂模式对于需要复杂初始化的装饰器可以使用类来实现装饰器工厂class DecoratorFactory: def __init__(self, **kwargs): self.options kwargs def __call__(self, func): wraps(func) def wrapper(*args, **kwargs): # 使用self.options中的配置 print(f装饰器配置: {self.options}) return func(*args, **kwargs) return wrapper DecoratorFactory(log_levelDEBUG, timeout10) def critical_operation(): pass6.3 装饰器与描述符装饰器可以与描述符协议结合实现更强大的功能class Validator: def __init__(self, validator_func): self.validator validator_func def __set_name__(self, owner, name): self.private_name f_{name} def __get__(self, obj, objtypeNone): return getattr(obj, self.private_name) def __set__(self, obj, value): if not self.validator(value): raise ValueError(f无效值: {value}) setattr(obj, self.private_name, value) def validate_age(value): return isinstance(value, int) and 0 value 150 class Person: age Validator(validate_age) def __init__(self, age): self.age age7. 装饰器的注意事项不要过度使用装饰器过多的装饰器会使代码难以理解和调试保持装饰器简单每个装饰器应该只负责一个明确的功能注意装饰器的执行顺序多个装饰器时靠近函数的装饰器先执行考虑性能影响装饰器会增加函数调用开销对性能敏感的场景要谨慎使用正确处理异常装饰器中应该捕获并适当处理异常或者重新抛出在实际项目中装饰器最常见的用途包括添加日志记录实现权限控制进行输入验证缓存函数结果测量执行时间事务管理重试机制掌握装饰器可以显著提高代码的可重用性和可维护性是Python程序员必须掌握的高级技巧之一。