乐闻世界logo
搜索文章和话题

Python 装饰器的高级应用有哪些?

2月17日 23:49

装饰器进阶概念

装饰器不仅可以用于简单的函数包装,还可以实现更复杂的功能,如参数化装饰器、类装饰器、装饰器链等。

装饰器的基本回顾

python
from functools import wraps def simple_decorator(func): @wraps(func) def wrapper(*args, **kwargs): print(f"调用函数: {func.__name__}") result = func(*args, **kwargs) print(f"函数返回: {result}") return result return wrapper @simple_decorator def add(a, b): return a + b add(3, 5) # 输出: # 调用函数: add # 函数返回: 8

参数化装饰器

带参数的装饰器

python
from functools import wraps def repeat(times): """重复执行函数指定次数的装饰器""" def decorator(func): @wraps(func) def wrapper(*args, **kwargs): results = [] for _ in range(times): result = func(*args, **kwargs) results.append(result) return results return wrapper return decorator @repeat(3) def greet(name): return f"Hello, {name}!" results = greet("Alice") print(results) # 输出: ['Hello, Alice!', 'Hello, Alice!', 'Hello, Alice!']

带可选参数的装饰器

python
from functools import wraps def logged(level="INFO"): """可配置日志级别的装饰器""" def decorator(func): @wraps(func) def wrapper(*args, **kwargs): print(f"[{level}] 调用函数: {func.__name__}") try: result = func(*args, **kwargs) print(f"[{level}] 函数返回: {result}") return result except Exception as e: print(f"[{level}] 函数异常: {e}") raise return wrapper return decorator # 使用默认日志级别 @logged() def function1(): return "Success" # 使用自定义日志级别 @logged(level="DEBUG") def function2(): return "Debug info" function1() function2()

类装饰器

基本类装饰器

python
def add_class_method(cls): """为类添加类方法的装饰器""" @classmethod def class_method(cls): return f"类方法: {cls.__name__}" cls.class_method = class_method return cls @add_class_method class MyClass: pass print(MyClass.class_method()) # 类方法: MyClass

单例装饰器

python
def singleton(cls): """单例模式装饰器""" instances = {} def get_instance(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return get_instance @singleton class Database: def __init__(self): self.connection = "Connected" db1 = Database() db2 = Database() print(db1 is db2) # True

注册装饰器

python
class PluginRegistry: """插件注册器""" def __init__(self): self.plugins = {} def register(self, name): def decorator(cls): self.plugins[name] = cls return cls return decorator def get_plugin(self, name): return self.plugins.get(name) registry = PluginRegistry() @registry.register("email") class EmailPlugin: def send(self, message): return f"发送邮件: {message}" @registry.register("sms") class SMSPlugin: def send(self, message): return f"发送短信: {message}" # 使用插件 email_plugin = registry.get_plugin("email") print(email_plugin().send("Hello"))

装饰器链

多个装饰器叠加

python
from functools import wraps def decorator1(func): @wraps(func) def wrapper(*args, **kwargs): print("装饰器1 - 前") result = func(*args, **kwargs) print("装饰器1 - 后") return result return wrapper def decorator2(func): @wraps(func) def wrapper(*args, **kwargs): print("装饰器2 - 前") result = func(*args, **kwargs) print("装饰器2 - 后") return result return wrapper @decorator1 @decorator2 def my_function(): print("执行函数") my_function() # 输出: # 装饰器1 - 前 # 装饰器2 - 前 # 执行函数 # 装饰器2 - 后 # 装饰器1 - 后

装饰器顺序的重要性

python
from functools import wraps def uppercase(func): @wraps(func) def wrapper(*args, **kwargs): result = func(*args, **kwargs) return result.upper() return wrapper def exclamation(func): @wraps(func) def wrapper(*args, **kwargs): result = func(*args, **kwargs) return f"{result}!" return wrapper # 不同的装饰器顺序产生不同的结果 @exclamation @uppercase def greet1(): return "hello" @uppercase @exclamation def greet2(): return "hello" print(greet1()) # HELLO! print(greet2()) # HELLO!

有状态的装饰器

计数装饰器

python
from functools import wraps def count_calls(func): """统计函数调用次数的装饰器""" @wraps(func) def wrapper(*args, **kwargs): wrapper.call_count += 1 print(f"函数 {func.__name__} 被调用了 {wrapper.call_count} 次") return func(*args, **kwargs) wrapper.call_count = 0 return wrapper @count_calls def calculate(x): return x * 2 calculate(5) calculate(10) calculate(15) # 输出: # 函数 calculate 被调用了 1 次 # 函数 calculate 被调用了 2 次 # 函数 calculate 被调用了 3 次

缓存装饰器

python
from functools import wraps def memoize(func): """记忆化装饰器""" cache = {} @wraps(func) def wrapper(*args, **kwargs): # 创建缓存键 key = (args, frozenset(kwargs.items())) if key not in cache: print(f"计算结果: {args}, {kwargs}") cache[key] = func(*args, **kwargs) else: print(f"使用缓存: {args}, {kwargs}") return cache[key] wrapper.cache = cache return wrapper @memoize def fibonacci(n): if n < 2: return n return fibonacci(n-1) + fibonacci(n-2) print(fibonacci(10)) print(fibonacci(10)) # 第二次使用缓存

方法装饰器

实例方法装饰器

python
from functools import wraps def method_decorator(func): @wraps(func) def wrapper(self, *args, **kwargs): print(f"调用方法: {func.__name__} 在实例 {self} 上") return func(self, *args, **kwargs) return wrapper class MyClass: @method_decorator def method(self, value): return value * 2 obj = MyClass() print(obj.method(5))

类方法装饰器

python
from functools import wraps def class_method_decorator(func): @wraps(func) def wrapper(cls, *args, **kwargs): print(f"调用类方法: {func.__name__} 在类 {cls} 上") return func(cls, *args, **kwargs) return wrapper class MyClass: @classmethod @class_method_decorator def class_method(cls): return f"类方法: {cls.__name__}" print(MyClass.class_method())

静态方法装饰器

python
from functools import wraps def static_method_decorator(func): @wraps(func) def wrapper(*args, **kwargs): print(f"调用静态方法: {func.__name__}") return func(*args, **kwargs) return wrapper class MyClass: @staticmethod @static_method_decorator def static_method(value): return value * 2 print(MyClass.static_method(5))

装饰器工厂

动态创建装饰器

python
from functools import wraps def create_validator(**validators): """创建验证装饰器的工厂函数""" def decorator(func): @wraps(func) def wrapper(*args, **kwargs): # 验证参数 for param_name, validator in validators.items(): if param_name in kwargs: value = kwargs[param_name] if not validator(value): raise ValueError(f"参数 {param_name} 验证失败: {value}") return func(*args, **kwargs) return wrapper return decorator # 定义验证器 def is_positive(x): return x > 0 def is_string(x): return isinstance(x, str) # 使用工厂创建装饰器 @create_validator(age=is_positive, name=is_string) def process_user(name, age): return f"用户: {name}, 年龄: {age}" print(process_user("Alice", 25)) # process_user("Alice", -5) # ValueError: 参数 age 验证失败: -5

装饰器与异步函数

异步函数装饰器

python
import asyncio from functools import wraps def async_decorator(func): """异步函数装饰器""" @wraps(func) async def wrapper(*args, **kwargs): print(f"异步调用函数: {func.__name__}") result = await func(*args, **kwargs) print(f"异步函数返回: {result}") return result return wrapper @async_decorator async def async_function(): await asyncio.sleep(1) return "异步完成" async def main(): result = await async_function() print(result) asyncio.run(main())

异步上下文管理器装饰器

python
import asyncio from functools import wraps def async_context_manager(func): """异步上下文管理器装饰器""" @wraps(func) async def wrapper(*args, **kwargs): print("进入异步上下文") try: result = await func(*args, **kwargs) return result finally: print("退出异步上下文") return wrapper @async_context_manager async def async_operation(): print("执行异步操作") await asyncio.sleep(0.5) return "操作完成" asyncio.run(async_operation())

实际应用场景

1. 权限验证装饰器

python
from functools import wraps def require_permission(permission): """权限验证装饰器""" def decorator(func): @wraps(func) def wrapper(self, *args, **kwargs): if not hasattr(self, 'permissions'): raise PermissionError("没有权限信息") if permission not in self.permissions: raise PermissionError(f"需要 {permission} 权限") return func(self, *args, **kwargs) return wrapper return decorator class User: def __init__(self, name, permissions): self.name = name self.permissions = permissions @require_permission('admin') def delete_user(self, user_id): return f"删除用户 {user_id}" @require_permission('write') def edit_post(self, post_id): return f"编辑文章 {post_id}" admin = User("Admin", ['admin', 'write']) user = User("User", ['read']) print(admin.delete_user(1)) # 删除用户 1 # user.delete_user(1) # PermissionError: 需要 admin 权限

2. 性能监控装饰器

python
import time from functools import wraps def performance_monitor(func): """性能监控装饰器""" @wraps(func) def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() execution_time = end_time - start_time print(f"函数 {func.__name__} 执行时间: {execution_time:.4f} 秒") return result return wrapper @performance_monitor def calculate_fibonacci(n): if n < 2: return n return calculate_fibonacci(n-1) + calculate_fibonacci(n-2) calculate_fibonacci(30)

3. 重试装饰器

python
import time from functools import wraps def retry(max_attempts=3, delay=1): """重试装饰器""" def decorator(func): @wraps(func) def wrapper(*args, **kwargs): last_exception = None for attempt in range(max_attempts): try: return func(*args, **kwargs) except Exception as e: last_exception = e if attempt < max_attempts - 1: print(f"尝试 {attempt + 1} 失败,{delay} 秒后重试...") time.sleep(delay) raise last_exception return wrapper return decorator @retry(max_attempts=3, delay=2) def unstable_function(): import random if random.random() < 0.7: raise ValueError("随机失败") return "成功" result = unstable_function() print(result)

4. 日志装饰器

python
import logging from functools import wraps def logged(func): """日志装饰器""" @wraps(func) def wrapper(*args, **kwargs): logging.info(f"调用函数: {func.__name__} 参数: args={args}, kwargs={kwargs}") try: result = func(*args, **kwargs) logging.info(f"函数 {func.__name__} 返回: {result}") return result except Exception as e: logging.error(f"函数 {func.__name__} 异常: {e}") raise return wrapper # 配置日志 logging.basicConfig(level=logging.INFO) @logged def divide(a, b): return a / b divide(10, 2) # divide(10, 0) # 会记录错误日志

5. 缓存装饰器

python
from functools import lru_cache import time @lru_cache(maxsize=128) def expensive_computation(n): """耗时计算""" print(f"计算 {n}...") time.sleep(1) return n ** 2 # 第一次调用 print(expensive_computation(5)) # 计算 5... 25 # 第二次调用(使用缓存) print(expensive_computation(5)) # 25(直接返回,不计算)

最佳实践

1. 使用 functools.wraps

python
from functools import wraps # 好的做法 - 保留函数元数据 def good_decorator(func): @wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper # 不好的做法 - 不保留函数元数据 def bad_decorator(func): def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper

2. 处理装饰器参数

python
from functools import wraps def decorator_with_args(*decorator_args, **decorator_kwargs): """支持参数的装饰器""" def decorator(func): @wraps(func) def wrapper(*args, **kwargs): # 使用装饰器参数 print(f"装饰器参数: {decorator_args}, {decorator_kwargs}") return func(*args, **kwargs) return wrapper return decorator @decorator_with_args("arg1", "arg2", kwarg1="value1") def my_function(): return "Hello" my_function()

3. 装饰器应该是无副作用的

python
from functools import wraps # 好的做法 - 无副作用 def pure_decorator(func): @wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper # 不好的做法 - 有副作用 counter = 0 def impure_decorator(func): @wraps(func) def wrapper(*args, **kwargs): global counter counter += 1 return func(*args, **kwargs) return wrapper

4. 提供清晰的文档

python
from functools import wraps def timing_decorator(func): """计时装饰器 这个装饰器用于测量函数的执行时间。 执行时间会打印到控制台。 示例: @timing_decorator def my_function(): time.sleep(1) return "Done" """ @wraps(func) def wrapper(*args, **kwargs): import time 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

总结

Python 装饰器高级应用的核心概念:

  1. 参数化装饰器:接受参数的装饰器,提供更多灵活性
  2. 类装饰器:用于装饰类,添加类级别的功能
  3. 装饰器链:多个装饰器叠加使用,注意执行顺序
  4. 有状态的装饰器:维护内部状态的装饰器
  5. 方法装饰器:用于装饰实例方法、类方法、静态方法
  6. 装饰器工厂:动态创建装饰器的函数
  7. 异步装饰器:用于装饰异步函数

装饰器的实际应用:

  • 权限验证
  • 性能监控
  • 错误处理和重试
  • 日志记录
  • 缓存和记忆化
  • 参数验证

装饰器的最佳实践:

  • 使用 functools.wraps 保留函数元数据
  • 正确处理装饰器参数
  • 保持装饰器的无副作用
  • 提供清晰的文档和示例
  • 考虑装饰器的性能影响

掌握装饰器的高级应用,能够编写出更强大、更灵活的 Python 代码。

标签:Python