021-装饰器原理与应用

021-装饰器原理与应用

🔴 难度: 高级 | ⏱️ 预计时间: 6小时 | 📋 前置: 020-文件操作与IO处理

学习目标

完成本章节后,你将能够:

  • 深入理解装饰器的工作原理和实现机制
  • 掌握函数装饰器、类装饰器和属性装饰器的使用
  • 学会创建带参数的装饰器和装饰器链
  • 理解装饰器在实际项目中的应用场景
  • 掌握装饰器的性能优化和最佳实践

装饰器基础概念

什么是装饰器

装饰器是Python中一种强大的语法糖,它允许我们在不修改原函数代码的情况下,为函数添加额外的功能。装饰器本质上是一个接受函数作为参数并返回新函数的高阶函数。

# 装饰器基础概念演示
print("\n=== 装饰器基础概念 ===")

# 最简单的装饰器
def my_decorator(func):
    """简单装饰器示例"""
    def wrapper():
        print("装饰器:函数执行前")
        result = func()
        print("装饰器:函数执行后")
        return result
    return wrapper

# 使用装饰器的两种方式

# 方式1:使用@语法糖
@my_decorator
def greet():
    """问候函数"""
    print("Hello, World!")
    return "greeting_done"

# 方式2:手动应用装饰器
def say_goodbye():
    """告别函数"""
    print("Goodbye, World!")
    return "goodbye_done"

say_goodbye = my_decorator(say_goodbye)

# 测试装饰器效果
print("\n使用@语法糖的装饰器:")
result1 = greet()
print(f"返回值: {result1}")

print("\n手动应用的装饰器:")
result2 = say_goodbye()
print(f"返回值: {result2}")

# 装饰器的本质:函数替换
print("\n装饰器的本质:")
print(f"greet函数名: {greet.__name__}")  # 注意:函数名变成了wrapper
print(f"greet函数类型: {type(greet)}")

装饰器的工作原理

# 装饰器工作原理详解
print("\n=== 装饰器工作原理 ===")

# 步骤分解演示
def step_by_step_decorator(func):
    """分步演示装饰器工作原理"""
    print(f"1. 装饰器被调用,接收函数: {func.__name__}")
    
    def wrapper(*args, **kwargs):
        print(f"3. wrapper被调用,参数: args={args}, kwargs={kwargs}")
        print("4. 执行原函数前的逻辑")
        result = func(*args, **kwargs)
        print("5. 执行原函数后的逻辑")
        return result
    
    print("2. 返回wrapper函数")
    return wrapper

print("\n装饰器应用过程:")
@step_by_step_decorator
def calculate(x, y):
    """计算函数"""
    print(f"6. 原函数执行: {x} + {y} = {x + y}")
    return x + y

print("\n调用被装饰的函数:")
result = calculate(3, 5)
print(f"最终结果: {result}")

函数装饰器

保留函数元信息

# 保留函数元信息
print("\n=== 保留函数元信息 ===")

import functools
from datetime import datetime

# 不保留元信息的装饰器
def bad_decorator(func):
    """不保留元信息的装饰器"""
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

# 保留元信息的装饰器
def good_decorator(func):
    """保留元信息的装饰器"""
    @functools.wraps(func)  # 关键:使用functools.wraps
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@bad_decorator
def bad_example():
    """这是一个示例函数"""
    pass

@good_decorator
def good_example():
    """这是一个示例函数"""
    pass

# 对比元信息保留情况
print("不保留元信息的装饰器:")
print(f"函数名: {bad_example.__name__}")  # wrapper
print(f"文档字符串: {bad_example.__doc__}")  # None

print("\n保留元信息的装饰器:")
print(f"函数名: {good_example.__name__}")  # good_example
print(f"文档字符串: {good_example.__doc__}")  # 这是一个示例函数

常用装饰器模式

# 常用装饰器模式
print("\n=== 常用装饰器模式 ===")

import time
import functools
from typing import Any, Callable

# 1. 计时装饰器
def timer(func: Callable) -> Callable:
    """计算函数执行时间的装饰器"""
    @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

# 2. 重试装饰器
def retry(max_attempts: int = 3, delay: float = 1.0):
    """重试装饰器"""
    def decorator(func: Callable) -> Callable:
        @functools.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"{func.__name__}{attempt + 1}次尝试失败: {e}")
                        time.sleep(delay)
                    else:
                        print(f"{func.__name__} 所有尝试都失败了")
            
            raise last_exception
        return wrapper
    return decorator

# 3. 缓存装饰器
def simple_cache(func: Callable) -> Callable:
    """简单缓存装饰器"""
    cache = {}
    
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 创建缓存键
        key = str(args) + str(sorted(kwargs.items()))
        
        if key in cache:
            print(f"缓存命中: {func.__name__}({args}, {kwargs})")
            return cache[key]
        
        print(f"计算结果: {func.__name__}({args}, {kwargs})")
        result = func(*args, **kwargs)
        cache[key] = result
        return result
    
    # 添加清除缓存的方法
    wrapper.clear_cache = lambda: cache.clear()
    wrapper.cache_info = lambda: f"缓存大小: {len(cache)}"
    
    return wrapper

# 4. 日志装饰器
def log_calls(level: str = "INFO"):
    """日志装饰器"""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 简化的日志记录
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            print(f"[{timestamp}] {level}: 调用 {func.__name__}")
            print(f"[{timestamp}] {level}: 参数 args={args}, kwargs={kwargs}")
            
            try:
                result = func(*args, **kwargs)
                print(f"[{timestamp}] {level}: {func.__name__} 执行成功")
                return result
            except Exception as e:
                print(f"[{timestamp}] ERROR: {func.__name__} 执行失败: {e}")
                raise
        return wrapper
    return decorator

# 测试装饰器
@timer
@simple_cache
@log_calls("DEBUG")
def fibonacci(n: int) -> int:
    """计算斐波那契数列"""
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

@retry(max_attempts=3, delay=0.5)
def unreliable_function(success_rate: float = 0.3):
    """模拟不稳定的函数"""
    import random
    if random.random() < success_rate:
        return "成功!"
    else:
        raise Exception("随机失败")

# 演示装饰器效果
print("\n=== 装饰器效果演示 ===")

print("\n1. 斐波那契数列计算(带缓存和计时):")
result = fibonacci(10)
print(f"fibonacci(10) = {result}")
print(fibonacci.cache_info())

print("\n2. 再次计算相同值(应该使用缓存):")
result = fibonacci(10)
print(f"fibonacci(10) = {result}")

print("\n3. 重试装饰器演示:")
try:
    result = unreliable_function(0.8)  # 80%成功率
    print(f"函数执行结果: {result}")
except Exception as e:
    print(f"最终失败: {e}")

带参数的装饰器

装饰器工厂

# 带参数的装饰器
print("\n=== 带参数的装饰器 ===")

import functools
from typing import Any, Callable, Optional

# 装饰器工厂模式
def validate_types(**expected_types):
    """类型验证装饰器工厂"""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 获取函数签名
            import inspect
            sig = inspect.signature(func)
            bound_args = sig.bind(*args, **kwargs)
            bound_args.apply_defaults()
            
            # 验证参数类型
            for param_name, expected_type in expected_types.items():
                if param_name in bound_args.arguments:
                    value = bound_args.arguments[param_name]
                    if not isinstance(value, expected_type):
                        raise TypeError(
                            f"参数 {param_name} 期望类型 {expected_type.__name__}, "
                            f"实际类型 {type(value).__name__}"
                        )
            
            return func(*args, **kwargs)
        return wrapper
    return decorator

# 权限检查装饰器
def require_permission(permission: str, user_getter: Callable = None):
    """权限检查装饰器"""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 模拟用户权限检查
            if user_getter:
                user = user_getter()
            else:
                # 从kwargs中获取用户信息
                user = kwargs.get('user', {'permissions': []})
            
            user_permissions = user.get('permissions', [])
            
            if permission not in user_permissions:
                raise PermissionError(f"需要权限: {permission}")
            
            print(f"权限检查通过: {permission}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

# 限流装饰器
def rate_limit(max_calls: int, time_window: int):
    """限流装饰器"""
    def decorator(func: Callable) -> Callable:
        calls = []
        
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            now = time.time()
            
            # 清理过期的调用记录
            calls[:] = [call_time for call_time in calls if now - call_time < time_window]
            
            # 检查是否超过限制
            if len(calls) >= max_calls:
                raise Exception(f"超过限流限制: {max_calls}次/{time_window}秒")
            
            calls.append(now)
            print(f"当前调用次数: {len(calls)}/{max_calls}")
            return func(*args, **kwargs)
        
        wrapper.reset_limit = lambda: calls.clear()
        return wrapper
    return decorator

# 条件装饰器
def conditional_decorator(condition: bool, decorator_func: Callable):
    """条件装饰器:只在满足条件时应用装饰器"""
    def decorator(func: Callable) -> Callable:
        if condition:
            return decorator_func(func)
        else:
            return func
    return decorator

# 测试带参数的装饰器
@validate_types(name=str, age=int, score=float)
def create_student(name: str, age: int, score: float = 0.0):
    """创建学生信息"""
    return {"name": name, "age": age, "score": score}

@require_permission("admin")
def delete_user(user_id: int, user: dict):
    """删除用户(需要管理员权限)"""
    print(f"删除用户: {user_id}")
    return f"用户 {user_id} 已删除"

@rate_limit(max_calls=3, time_window=5)
def api_call(data: str):
    """API调用(限流:5秒内最多3次)"""
    print(f"处理API请求: {data}")
    return f"处理完成: {data}"

# 条件装饰器示例
DEBUG_MODE = True

@conditional_decorator(DEBUG_MODE, timer)
def process_data(data: list):
    """处理数据(调试模式下计时)"""
    return sum(data)

# 演示带参数装饰器
print("\n=== 带参数装饰器演示 ===")

print("\n1. 类型验证装饰器:")
try:
    student = create_student("张三", 20, 95.5)
    print(f"创建学生成功: {student}")
    
    # 类型错误示例
    student = create_student("李四", "二十", 90.0)  # age应该是int
except TypeError as e:
    print(f"类型验证失败: {e}")

print("\n2. 权限检查装饰器:")
try:
    # 有权限的用户
    admin_user = {"permissions": ["admin", "read", "write"]}
    result = delete_user(123, user=admin_user)
    print(f"操作成功: {result}")
    
    # 无权限的用户
    normal_user = {"permissions": ["read"]}
    result = delete_user(456, user=normal_user)
except PermissionError as e:
    print(f"权限检查失败: {e}")

print("\n3. 限流装饰器:")
try:
    for i in range(5):
        result = api_call(f"请求{i+1}")
        time.sleep(0.5)
except Exception as e:
    print(f"限流触发: {e}")

print("\n4. 条件装饰器:")
result = process_data([1, 2, 3, 4, 5])
print(f"处理结果: {result}")

类装饰器

装饰器类的实现

# 类装饰器
print("\n=== 类装饰器 ===")

import functools
from typing import Any, Callable

# 1. 使用类实现装饰器
class CountCalls:
    """统计函数调用次数的装饰器类"""
    
    def __init__(self, func: Callable):
        self.func = func
        self.count = 0
        # 保留原函数的元信息
        functools.update_wrapper(self, func)
    
    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"{self.func.__name__} 被调用第 {self.count} 次")
        return self.func(*args, **kwargs)
    
    def reset_count(self):
        """重置计数器"""
        self.count = 0
    
    def get_count(self):
        """获取调用次数"""
        return self.count

# 2. 带参数的装饰器类
class Memoize:
    """记忆化装饰器类"""
    
    def __init__(self, max_size: int = 128):
        self.max_size = max_size
        self.cache = {}
        self.access_order = []
    
    def __call__(self, func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 创建缓存键
            key = self._make_key(args, kwargs)
            
            if key in self.cache:
                # 更新访问顺序
                self.access_order.remove(key)
                self.access_order.append(key)
                print(f"缓存命中: {func.__name__}{args}")
                return self.cache[key]
            
            # 计算结果
            result = func(*args, **kwargs)
            
            # 缓存管理
            if len(self.cache) >= self.max_size:
                # 移除最久未使用的项
                oldest_key = self.access_order.pop(0)
                del self.cache[oldest_key]
            
            self.cache[key] = result
            self.access_order.append(key)
            print(f"计算并缓存: {func.__name__}{args}")
            return result
        
        # 添加缓存管理方法
        wrapper.cache_clear = self.clear_cache
        wrapper.cache_info = self.cache_info
        
        return wrapper
    
    def _make_key(self, args, kwargs):
        """创建缓存键"""
        return str(args) + str(sorted(kwargs.items()))
    
    def clear_cache(self):
        """清空缓存"""
        self.cache.clear()
        self.access_order.clear()
    
    def cache_info(self):
        """获取缓存信息"""
        return f"缓存大小: {len(self.cache)}/{self.max_size}"

# 3. 装饰类的装饰器
def add_repr(cls):
    """为类添加__repr__方法的装饰器"""
    def __repr__(self):
        class_name = self.__class__.__name__
        attrs = []
        for key, value in self.__dict__.items():
            if not key.startswith('_'):
                attrs.append(f"{key}={value!r}")
        return f"{class_name}({', '.join(attrs)})"
    
    cls.__repr__ = __repr__
    return cls

def singleton(cls):
    """单例模式装饰器"""
    instances = {}
    
    @functools.wraps(cls)
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    
    return get_instance

def auto_property(cls):
    """自动为类属性添加getter/setter的装饰器"""
    for name, value in list(cls.__dict__.items()):
        if not name.startswith('_') and not callable(value):
            # 创建私有属性
            private_name = f'_{name}'
            
            # 创建getter和setter
            def make_property(attr_name, private_attr):
                def getter(self):
                    return getattr(self, private_attr, None)
                
                def setter(self, value):
                    setattr(self, private_attr, value)
                
                return property(getter, setter)
            
            # 添加属性
            setattr(cls, name, make_property(name, private_name))
    
    return cls

# 测试类装饰器
@CountCalls
def greet(name: str):
    """问候函数"""
    return f"Hello, {name}!"

@Memoize(max_size=3)
def expensive_calculation(n: int):
    """模拟耗时计算"""
    print(f"正在计算 {n} 的平方...")
    time.sleep(0.1)  # 模拟耗时操作
    return n ** 2

@add_repr
@singleton
class DatabaseConnection:
    """数据库连接类"""
    
    def __init__(self, host: str = "localhost", port: int = 5432):
        self.host = host
        self.port = port
        self.connected = False
        print(f"创建数据库连接: {host}:{port}")
    
    def connect(self):
        self.connected = True
        print("数据库连接已建立")
    
    def disconnect(self):
        self.connected = False
        print("数据库连接已断开")

@auto_property
class Person:
    """人员类(自动属性)"""
    
    def __init__(self, name: str = "", age: int = 0):
        self.name = name
        self.age = age

# 演示类装饰器
print("\n=== 类装饰器演示 ===")

print("\n1. 函数调用计数装饰器:")
for i in range(3):
    result = greet(f"用户{i+1}")
    print(f"结果: {result}")
print(f"总调用次数: {greet.get_count()}")

print("\n2. 记忆化装饰器:")
for i in [1, 2, 3, 2, 1, 4, 3]:
    result = expensive_calculation(i)
    print(f"结果: {result}")
print(expensive_calculation.cache_info())

print("\n3. 单例模式装饰器:")
db1 = DatabaseConnection("server1", 5432)
db2 = DatabaseConnection("server2", 3306)  # 参数被忽略
print(f"db1 is db2: {db1 is db2}")
print(f"db1: {db1}")
print(f"db2: {db2}")

print("\n4. 自动属性装饰器:")
person = Person()
person.name = "张三"  # 使用setter
person.age = 25
print(f"姓名: {person.name}")  # 使用getter
print(f"年龄: {person.age}")
print(f"私有属性: {person.__dict__}")  # 查看实际存储

装饰器链和组合

多装饰器的执行顺序

# 装饰器链和组合
print("\n=== 装饰器链和组合 ===")

import functools
from typing import Callable

# 创建几个简单的装饰器来演示执行顺序
def decorator_a(func: Callable) -> Callable:
    """装饰器A"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("装饰器A: 执行前")
        result = func(*args, **kwargs)
        print("装饰器A: 执行后")
        return result
    return wrapper

def decorator_b(func: Callable) -> Callable:
    """装饰器B"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("装饰器B: 执行前")
        result = func(*args, **kwargs)
        print("装饰器B: 执行后")
        return result
    return wrapper

def decorator_c(func: Callable) -> Callable:
    """装饰器C"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("装饰器C: 执行前")
        result = func(*args, **kwargs)
        print("装饰器C: 执行后")
        return result
    return wrapper

# 装饰器链的应用
@decorator_a
@decorator_b
@decorator_c
def test_function():
    """测试函数"""
    print("原函数执行")
    return "test_result"

print("\n装饰器链执行顺序演示:")
print("应用顺序: @decorator_a @decorator_b @decorator_c")
print("等价于: decorator_a(decorator_b(decorator_c(test_function)))")
print("\n执行结果:")
result = test_function()
print(f"返回值: {result}")

装饰器组合模式

# 装饰器组合模式
print("\n=== 装饰器组合模式 ===")

import functools
from typing import Callable, List

# 装饰器组合器
def compose_decorators(*decorators):
    """组合多个装饰器"""
    def decorator(func: Callable) -> Callable:
        for dec in reversed(decorators):
            func = dec(func)
        return func
    return decorator

# 条件装饰器组合
def conditional_compose(**conditions):
    """根据条件组合装饰器"""
    def decorator(func: Callable) -> Callable:
        for condition, decorator_func in conditions.items():
            if condition:
                func = decorator_func(func)
        return func
    return decorator

# 创建一些实用装饰器
def validate_input(func: Callable) -> Callable:
    """输入验证装饰器"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("验证输入参数...")
        # 这里可以添加具体的验证逻辑
        return func(*args, **kwargs)
    return wrapper

def log_execution(func: Callable) -> Callable:
    """执行日志装饰器"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"开始执行: {func.__name__}")
        try:
            result = func(*args, **kwargs)
            print(f"执行成功: {func.__name__}")
            return result
        except Exception as e:
            print(f"执行失败: {func.__name__}, 错误: {e}")
            raise
    return wrapper

def measure_performance(func: Callable) -> Callable:
    """性能测量装饰器"""
    @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

# 使用装饰器组合
@compose_decorators(validate_input, log_execution, measure_performance)
def complex_calculation(x: int, y: int) -> int:
    """复杂计算函数"""
    time.sleep(0.1)  # 模拟耗时操作
    return x ** y

# 条件装饰器组合示例
DEBUG_MODE = True
PRODUCTION_MODE = False

@conditional_compose(
    DEBUG_MODE=log_execution,
    PRODUCTION_MODE=measure_performance,
    True=validate_input  # 总是应用
)
def api_endpoint(data: dict) -> dict:
    """API端点函数"""
    return {"processed": True, "data": data}

# 演示装饰器组合
print("\n=== 装饰器组合演示 ===")

print("\n1. 使用compose_decorators:")
result = complex_calculation(2, 10)
print(f"计算结果: {result}")

print("\n2. 使用conditional_compose:")
result = api_endpoint({"key": "value"})
print(f"API结果: {result}")

属性装饰器

property装饰器详解

# 属性装饰器
print("\n=== 属性装饰器 ===")

import functools
from typing import Any, Optional

# 基础property使用
class Temperature:
    """温度类 - 演示property装饰器"""
    
    def __init__(self, celsius: float = 0.0):
        self._celsius = celsius
    
    @property
    def celsius(self) -> float:
        """摄氏温度getter"""
        return self._celsius
    
    @celsius.setter
    def celsius(self, value: float) -> None:
        """摄氏温度setter"""
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度(-273.15°C)")
        self._celsius = value
    
    @celsius.deleter
    def celsius(self) -> None:
        """摄氏温度deleter"""
        print("删除温度数据")
        self._celsius = 0.0
    
    @property
    def fahrenheit(self) -> float:
        """华氏温度(只读属性)"""
        return self._celsius * 9/5 + 32
    
    @property
    def kelvin(self) -> float:
        """开尔文温度(只读属性)"""
        return self._celsius + 273.15
    
    def __repr__(self):
        return f"Temperature({self._celsius}°C)"

# 高级property模式
class ValidatedProperty:
    """验证属性描述符"""
    
    def __init__(self, validator: Callable[[Any], bool] = None, 
                 error_message: str = "Invalid value"):
        self.validator = validator
        self.error_message = error_message
        self.name = None
    
    def __set_name__(self, owner, name):
        self.name = f'_{name}'
    
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return getattr(obj, self.name, None)
    
    def __set__(self, obj, value):
        if self.validator and not self.validator(value):
            raise ValueError(self.error_message)
        setattr(obj, self.name, value)
    
    def __delete__(self, obj):
        delattr(obj, self.name)

# 缓存属性装饰器
class cached_property:
    """缓存属性装饰器"""
    
    def __init__(self, func):
        self.func = func
        self.name = func.__name__
        self.__doc__ = func.__doc__
    
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        
        # 检查是否已缓存
        cache_name = f'_cached_{self.name}'
        if hasattr(obj, cache_name):
            return getattr(obj, cache_name)
        
        # 计算并缓存结果
        value = self.func(obj)
        setattr(obj, cache_name, value)
        return value
    
    def __delete__(self, obj):
        cache_name = f'_cached_{self.name}'
        if hasattr(obj, cache_name):
            delattr(obj, cache_name)

# 使用高级属性装饰器的类
class Person:
    """人员类 - 演示高级属性装饰器"""
    
    # 使用验证属性
    name = ValidatedProperty(
        validator=lambda x: isinstance(x, str) and len(x) > 0,
        error_message="姓名必须是非空字符串"
    )
    
    age = ValidatedProperty(
        validator=lambda x: isinstance(x, int) and 0 <= x <= 150,
        error_message="年龄必须是0-150之间的整数"
    )
    
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age
    
    @cached_property
    def full_info(self) -> str:
        """完整信息(缓存属性)"""
        print("计算完整信息...")  # 只在第一次访问时执行
        return f"姓名: {self.name}, 年龄: {self.age}岁"
    
    @property
    def is_adult(self) -> bool:
        """是否成年(只读属性)"""
        return self.age >= 18
    
    @property
    def age_group(self) -> str:
        """年龄组(只读属性)"""
        if self.age < 13:
            return "儿童"
        elif self.age < 18:
            return "青少年"
        elif self.age < 60:
            return "成年人"
        else:
            return "老年人"

# 演示属性装饰器
print("\n=== 属性装饰器演示 ===")

print("\n1. 基础property装饰器:")
temp = Temperature(25.0)
print(f"初始温度: {temp}")
print(f"摄氏温度: {temp.celsius}°C")
print(f"华氏温度: {temp.fahrenheit}°F")
print(f"开尔文温度: {temp.kelvin}K")

# 修改温度
temp.celsius = 100.0
print(f"\n修改后: {temp}")
print(f"华氏温度: {temp.fahrenheit}°F")

# 温度验证
try:
    temp.celsius = -300.0  # 低于绝对零度
except ValueError as e:
    print(f"温度验证失败: {e}")

print("\n2. 高级属性装饰器:")
person = Person("张三", 25)
print(f"姓名: {person.name}")
print(f"年龄: {person.age}")
print(f"是否成年: {person.is_adult}")
print(f"年龄组: {person.age_group}")

# 缓存属性演示
print("\n3. 缓存属性演示:")
print("第一次访问full_info:")
info1 = person.full_info
print(f"结果: {info1}")

print("\n第二次访问full_info(使用缓存):")
info2 = person.full_info
print(f"结果: {info2}")

# 属性验证演示
print("\n4. 属性验证演示:")
try:
    person.age = -5  # 无效年龄
except ValueError as e:
    print(f"年龄验证失败: {e}")

try:
    person.name = ""  # 空姓名
except ValueError as e:
    print(f"姓名验证失败: {e}")

装饰器的实际应用

Web框架中的装饰器

# Web框架中的装饰器应用
print("\n=== Web框架装饰器应用 ===")

import functools
import json
from typing import Callable, Dict, Any
from datetime import datetime, timedelta

# 模拟Web框架的装饰器
class Request:
    """模拟HTTP请求对象"""
    def __init__(self, method: str = "GET", path: str = "/", 
                 headers: Dict[str, str] = None, data: Any = None):
        self.method = method
        self.path = path
        self.headers = headers or {}
        self.data = data
        self.user = None  # 用户信息

class Response:
    """模拟HTTP响应对象"""
    def __init__(self, data: Any, status_code: int = 200, 
                 headers: Dict[str, str] = None):
        self.data = data
        self.status_code = status_code
        self.headers = headers or {}

# 路由装饰器
def route(path: str, methods: list = None):
    """路由装饰器"""
    if methods is None:
        methods = ["GET"]
    
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(request: Request, *args, **kwargs):
            # 检查HTTP方法
            if request.method not in methods:
                return Response(
                    {"error": f"Method {request.method} not allowed"}, 
                    status_code=405
                )
            
            # 检查路径匹配
            if request.path != path:
                return Response(
                    {"error": "Path not found"}, 
                    status_code=404
                )
            
            return func(request, *args, **kwargs)
        
        # 添加路由信息
        wrapper._route_path = path
        wrapper._route_methods = methods
        return wrapper
    return decorator

# 身份验证装饰器
def require_auth(func: Callable) -> Callable:
    """身份验证装饰器"""
    @functools.wraps(func)
    def wrapper(request: Request, *args, **kwargs):
        # 检查Authorization头
        auth_header = request.headers.get("Authorization")
        if not auth_header or not auth_header.startswith("Bearer "):
            return Response(
                {"error": "Missing or invalid authorization header"}, 
                status_code=401
            )
        
        # 模拟token验证
        token = auth_header[7:]  # 移除"Bearer "
        if token != "valid_token":
            return Response(
                {"error": "Invalid token"}, 
                status_code=401
            )
        
        # 设置用户信息
        request.user = {"id": 1, "username": "admin"}
        return func(request, *args, **kwargs)
    
    return wrapper

# JSON响应装饰器
def json_response(func: Callable) -> Callable:
    """JSON响应装饰器"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        
        if isinstance(result, Response):
            return result
        
        # 将结果转换为JSON响应
        return Response(
            result, 
            headers={"Content-Type": "application/json"}
        )
    
    return wrapper

# 请求验证装饰器
def validate_json(schema: Dict[str, type]):
    """JSON请求验证装饰器"""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(request: Request, *args, **kwargs):
            if not request.data:
                return Response(
                    {"error": "Missing request data"}, 
                    status_code=400
                )
            
            # 验证数据结构
            for field, expected_type in schema.items():
                if field not in request.data:
                    return Response(
                        {"error": f"Missing field: {field}"}, 
                        status_code=400
                    )
                
                if not isinstance(request.data[field], expected_type):
                    return Response(
                        {"error": f"Invalid type for {field}"}, 
                        status_code=400
                    )
            
            return func(request, *args, **kwargs)
        return wrapper
    return decorator

# 缓存装饰器
def cache_response(ttl: int = 300):
    """响应缓存装饰器"""
    cache = {}
    
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(request: Request, *args, **kwargs):
            # 创建缓存键
            cache_key = f"{request.method}:{request.path}:{str(request.data)}"
            
            # 检查缓存
            if cache_key in cache:
                cached_data, timestamp = cache[cache_key]
                if datetime.now() - timestamp < timedelta(seconds=ttl):
                    print(f"缓存命中: {cache_key}")
                    return cached_data
                else:
                    del cache[cache_key]
            
            # 执行函数并缓存结果
            result = func(request, *args, **kwargs)
            cache[cache_key] = (result, datetime.now())
            print(f"缓存存储: {cache_key}")
            return result
        
        wrapper.clear_cache = lambda: cache.clear()
        return wrapper
    return decorator

# 使用装饰器的API端点
@route("/api/users", methods=["GET"])
@json_response
@cache_response(ttl=60)
def get_users(request: Request):
    """获取用户列表"""
    return {
        "users": [
            {"id": 1, "name": "张三"},
            {"id": 2, "name": "李四"}
        ]
    }

@route("/api/users", methods=["POST"])
@require_auth
@validate_json({"name": str, "email": str})
@json_response
def create_user(request: Request):
    """创建用户"""
    user_data = request.data
    new_user = {
        "id": 3,
        "name": user_data["name"],
        "email": user_data["email"],
        "created_by": request.user["username"]
    }
    return {"user": new_user, "message": "User created successfully"}

@route("/api/protected", methods=["GET"])
@require_auth
@json_response
def protected_endpoint(request: Request):
    """受保护的端点"""
    return {
        "message": "This is a protected endpoint",
        "user": request.user
    }

# 演示Web框架装饰器
print("\n=== Web框架装饰器演示 ===")

print("\n1. 获取用户列表(缓存演示):")
request1 = Request("GET", "/api/users")
response1 = get_users(request1)
print(f"响应: {response1.data}")
print(f"状态码: {response1.status_code}")

print("\n再次请求(应该使用缓存):")
response1_cached = get_users(request1)
print(f"响应: {response1_cached.data}")

print("\n2. 创建用户(需要认证和验证):")
request2 = Request(
    "POST", 
    "/api/users",
    headers={"Authorization": "Bearer valid_token"},
    data={"name": "王五", "email": "wangwu@example.com"}
)
response2 = create_user(request2)
print(f"响应: {response2.data}")
print(f"状态码: {response2.status_code}")

print("\n3. 无效认证示例:")
request3 = Request(
    "POST", 
    "/api/users",
    headers={"Authorization": "Bearer invalid_token"},
    data={"name": "赵六", "email": "zhaoliu@example.com"}
)
response3 = create_user(request3)
print(f"响应: {response3.data}")
print(f"状态码: {response3.status_code}")

print("\n4. 数据验证失败示例:")
request4 = Request(
    "POST", 
    "/api/users",
    headers={"Authorization": "Bearer valid_token"},
    data={"name": "孙七"}  # 缺少email字段
)
response4 = create_user(request4)
print(f"响应: {response4.data}")
print(f"状态码: {response4.status_code}")

数据库操作装饰器

# 数据库操作装饰器
print("\n=== 数据库操作装饰器 ===")

import functools
import sqlite3
from contextlib import contextmanager
from typing import Callable, Any

# 模拟数据库连接管理
class DatabaseManager:
    """数据库管理器"""
    
    def __init__(self, db_path: str = ":memory:"):
        self.db_path = db_path
        self.connection = None
    
    def connect(self):
        """建立数据库连接"""
        if not self.connection:
            self.connection = sqlite3.connect(self.db_path)
            self.connection.row_factory = sqlite3.Row  # 返回字典格式
            print("数据库连接已建立")
    
    def disconnect(self):
        """关闭数据库连接"""
        if self.connection:
            self.connection.close()
            self.connection = None
            print("数据库连接已关闭")
    
    @contextmanager
    def transaction(self):
        """事务上下文管理器"""
        if not self.connection:
            self.connect()
        
        try:
            yield self.connection
            self.connection.commit()
            print("事务提交成功")
        except Exception as e:
            self.connection.rollback()
            print(f"事务回滚: {e}")
            raise

# 全局数据库管理器
db_manager = DatabaseManager()

# 数据库连接装饰器
def with_db_connection(func: Callable) -> Callable:
    """自动管理数据库连接的装饰器"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        db_manager.connect()
        try:
            # 将数据库连接作为第一个参数传递
            return func(db_manager.connection, *args, **kwargs)
        finally:
            db_manager.disconnect()
    return wrapper

# 事务装饰器
def with_transaction(func: Callable) -> Callable:
    """自动管理事务的装饰器"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        with db_manager.transaction() as conn:
            return func(conn, *args, **kwargs)
    return wrapper

# 查询结果转换装饰器
def convert_result(converter: Callable = None):
    """查询结果转换装饰器"""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            result = func(*args, **kwargs)
            
            if converter and result:
                if isinstance(result, list):
                    return [converter(row) for row in result]
                else:
                    return converter(result)
            
            return result
        return wrapper
    return decorator

# 查询缓存装饰器
def cache_query(ttl: int = 300):
    """查询缓存装饰器"""
    cache = {}
    
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 创建缓存键(排除数据库连接参数)
            cache_key = f"{func.__name__}:{str(args[1:])}:{str(kwargs)}"
            
            # 检查缓存
            if cache_key in cache:
                cached_data, timestamp = cache[cache_key]
                if datetime.now() - timestamp < timedelta(seconds=ttl):
                    print(f"查询缓存命中: {func.__name__}")
                    return cached_data
                else:
                    del cache[cache_key]
            
            # 执行查询并缓存结果
            result = func(*args, **kwargs)
            cache[cache_key] = (result, datetime.now())
            print(f"查询结果已缓存: {func.__name__}")
            return result
        
        wrapper.clear_cache = lambda: cache.clear()
        return wrapper
    return decorator

# 重试装饰器(针对数据库操作)
def retry_db_operation(max_attempts: int = 3, delay: float = 1.0):
    """数据库操作重试装饰器"""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            last_exception = None
            
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except (sqlite3.OperationalError, sqlite3.DatabaseError) as e:
                    last_exception = e
                    if attempt < max_attempts - 1:
                        print(f"数据库操作失败,第{attempt + 1}次重试: {e}")
                        time.sleep(delay)
                    else:
                        print(f"数据库操作最终失败: {e}")
            
            raise last_exception
        return wrapper
    return decorator

# 数据库操作函数示例
@with_db_connection
def init_database(conn):
    """初始化数据库"""
    conn.execute("""
        CREATE TABLE IF NOT EXISTS users (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            email TEXT UNIQUE NOT NULL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    """)
    conn.commit()
    print("数据库初始化完成")

@with_transaction
@retry_db_operation(max_attempts=3)
def create_user(conn, name: str, email: str):
    """创建用户"""
    cursor = conn.execute(
        "INSERT INTO users (name, email) VALUES (?, ?)",
        (name, email)
    )
    user_id = cursor.lastrowid
    print(f"用户创建成功,ID: {user_id}")
    return user_id

@with_db_connection
@cache_query(ttl=60)
@convert_result(lambda row: dict(row) if row else None)
def get_user_by_id(conn, user_id: int):
    """根据ID获取用户"""
    cursor = conn.execute(
        "SELECT * FROM users WHERE id = ?",
        (user_id,)
    )
    result = cursor.fetchone()
    print(f"查询用户: {user_id}")
    return result

@with_db_connection
@cache_query(ttl=30)
@convert_result(lambda rows: [dict(row) for row in rows])
def get_all_users(conn):
    """获取所有用户"""
    cursor = conn.execute("SELECT * FROM users ORDER BY created_at DESC")
    result = cursor.fetchall()
    print(f"查询所有用户,共 {len(result)} 条记录")
    return result

@with_transaction
def update_user(conn, user_id: int, name: str = None, email: str = None):
    """更新用户信息"""
    updates = []
    params = []
    
    if name:
        updates.append("name = ?")
        params.append(name)
    
    if email:
        updates.append("email = ?")
        params.append(email)
    
    if not updates:
        return False
    
    params.append(user_id)
    sql = f"UPDATE users SET {', '.join(updates)} WHERE id = ?"
    
    cursor = conn.execute(sql, params)
    affected_rows = cursor.rowcount
    print(f"更新用户 {user_id},影响行数: {affected_rows}")
    return affected_rows > 0

@with_transaction
def delete_user(conn, user_id: int):
    """删除用户"""
    cursor = conn.execute("DELETE FROM users WHERE id = ?", (user_id,))
    affected_rows = cursor.rowcount
    print(f"删除用户 {user_id},影响行数: {affected_rows}")
    return affected_rows > 0

# 演示数据库装饰器
print("\n=== 数据库装饰器演示 ===")

print("\n1. 初始化数据库:")
init_database()

print("\n2. 创建用户:")
user1_id = create_user("张三", "zhangsan@example.com")
user2_id = create_user("李四", "lisi@example.com")
user3_id = create_user("王五", "wangwu@example.com")

print("\n3. 查询用户(缓存演示):")
user = get_user_by_id(user1_id)
print(f"用户信息: {user}")

print("\n再次查询同一用户(应该使用缓存):")
user_cached = get_user_by_id(user1_id)
print(f"用户信息: {user_cached}")

print("\n4. 获取所有用户:")
all_users = get_all_users()
for user in all_users:
    print(f"  - {user['name']} ({user['email']})")

print("\n5. 更新用户:")
update_result = update_user(user2_id, name="李四(已更新)")
print(f"更新结果: {update_result}")

print("\n6. 删除用户:")
delete_result = delete_user(user3_id)
print(f"删除结果: {delete_result}")

装饰器性能优化

装饰器的性能考虑

# 装饰器性能优化
print("\n=== 装饰器性能优化 ===")

import functools
import time
from typing import Callable

# 性能测试装饰器
def performance_test(iterations: int = 1000000):
    """性能测试装饰器"""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 测试函数执行时间
            start_time = time.time()
            
            for _ in range(iterations):
                result = func(*args, **kwargs)
            
            end_time = time.time()
            total_time = end_time - start_time
            avg_time = total_time / iterations
            
            print(f"{func.__name__} 性能测试:")
            print(f"  总执行时间: {total_time:.6f}秒")
            print(f"  平均执行时间: {avg_time:.9f}秒")
            print(f"  每秒执行次数: {1/avg_time:.0f}次")
            
            return result
        return wrapper
    return decorator

# 轻量级装饰器(性能优化版本)
def lightweight_timer(func: Callable) -> Callable:
    """轻量级计时装饰器"""
    @functools.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

# 条件性装饰器(避免不必要的开销)
def conditional_timer(enabled: bool = True):
    """条件性计时装饰器"""
    def decorator(func: Callable) -> Callable:
        if not enabled:
            return func  # 直接返回原函数,避免装饰器开销
        
        @functools.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
    return decorator

# 缓存优化装饰器
class OptimizedCache:
    """优化的缓存装饰器"""
    
    def __init__(self, max_size: int = 128, ttl: int = 300):
        self.max_size = max_size
        self.ttl = ttl
        self.cache = {}
        self.access_times = {}
        self.creation_times = {}
    
    def __call__(self, func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 快速键生成
            key = hash((args, tuple(sorted(kwargs.items()))))
            current_time = time.time()
            
            # 检查缓存
            if key in self.cache:
                # 检查TTL
                if current_time - self.creation_times[key] < self.ttl:
                    self.access_times[key] = current_time
                    return self.cache[key]
                else:
                    # 过期清理
                    del self.cache[key]
                    del self.access_times[key]
                    del self.creation_times[key]
            
            # 计算结果
            result = func(*args, **kwargs)
            
            # 缓存管理
            if len(self.cache) >= self.max_size:
                # 移除最久未访问的项
                oldest_key = min(self.access_times.keys(), 
                               key=lambda k: self.access_times[k])
                del self.cache[oldest_key]
                del self.access_times[oldest_key]
                del self.creation_times[oldest_key]
            
            # 存储结果
            self.cache[key] = result
            self.access_times[key] = current_time
            self.creation_times[key] = current_time
            
            return result
        
        wrapper.cache_clear = self.clear_cache
        wrapper.cache_info = self.cache_info
        return wrapper
    
    def clear_cache(self):
        self.cache.clear()
        self.access_times.clear()
        self.creation_times.clear()
    
    def cache_info(self):
        return {
            "size": len(self.cache),
            "max_size": self.max_size,
            "hit_rate": "N/A"  # 可以添加命中率统计
        }

# 测试函数
def simple_function(x: int) -> int:
    """简单函数"""
    return x * 2

@lightweight_timer
def decorated_function(x: int) -> int:
    """装饰的函数"""
    return x * 2

@conditional_timer(enabled=False)
def conditionally_decorated(x: int) -> int:
    """条件装饰的函数"""
    return x * 2

@OptimizedCache(max_size=100, ttl=60)
def cached_fibonacci(n: int) -> int:
    """缓存的斐波那契函数"""
    if n <= 1:
        return n
    return cached_fibonacci(n - 1) + cached_fibonacci(n - 2)

# 性能对比测试
print("\n=== 装饰器性能对比 ===")

print("\n1. 无装饰器 vs 有装饰器性能对比:")

@performance_test(iterations=100000)
def test_simple():
    return simple_function(42)

@performance_test(iterations=100000)
def test_decorated():
    return decorated_function(42)

@performance_test(iterations=100000)
def test_conditional():
    return conditionally_decorated(42)

test_simple()
test_decorated()
test_conditional()

print("\n2. 缓存装饰器性能测试:")
start_time = time.time()
result = cached_fibonacci(30)
end_time = time.time()
print(f"cached_fibonacci(30) = {result}")
print(f"执行时间: {end_time - start_time:.6f}秒")
print(f"缓存信息: {cached_fibonacci.cache_info()}")

装饰器最佳实践

设计原则和注意事项

# 装饰器最佳实践
print("\n=== 装饰器最佳实践 ===")

import functools
import inspect
from typing import Callable, Any, TypeVar, ParamSpec

# 1. 保持函数签名的装饰器
def preserve_signature(func: Callable) -> Callable:
    """保持函数签名的装饰器示例"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"调用 {func.__name__}")
        return func(*args, **kwargs)
    
    # 保持原函数的签名信息
    wrapper.__signature__ = inspect.signature(func)
    return wrapper

# 2. 类型安全的装饰器
P = ParamSpec('P')
T = TypeVar('T')

def type_safe_decorator(func: Callable[P, T]) -> Callable[P, T]:
    """类型安全的装饰器"""
    @functools.wraps(func)
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
        print(f"类型安全调用: {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

# 3. 可配置的装饰器工厂
class ConfigurableDecorator:
    """可配置的装饰器类"""
    
    def __init__(self, **config):
        self.config = config
        self.enabled = config.get('enabled', True)
        self.log_level = config.get('log_level', 'INFO')
        self.include_args = config.get('include_args', False)
    
    def __call__(self, func: Callable) -> Callable:
        if not self.enabled:
            return func
        
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if self.include_args:
                print(f"[{self.log_level}] 调用 {func.__name__} with args={args}, kwargs={kwargs}")
            else:
                print(f"[{self.log_level}] 调用 {func.__name__}")
            
            return func(*args, **kwargs)
        return wrapper

# 4. 装饰器注册模式
class DecoratorRegistry:
    """装饰器注册器"""
    
    def __init__(self):
        self.functions = {}
        self.middleware = []
    
    def register(self, name: str = None):
        """注册装饰器"""
        def decorator(func: Callable) -> Callable:
            func_name = name or func.__name__
            self.functions[func_name] = func
            
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                # 应用中间件
                for middleware in self.middleware:
                    middleware(func, args, kwargs)
                
                return func(*args, **kwargs)
            return wrapper
        return decorator
    
    def add_middleware(self, middleware: Callable):
        """添加中间件"""
        self.middleware.append(middleware)
    
    def get_function(self, name: str):
        """获取注册的函数"""
        return self.functions.get(name)
    
    def list_functions(self):
        """列出所有注册的函数"""
        return list(self.functions.keys())

# 5. 错误处理装饰器
def robust_decorator(default_return=None, exceptions=(Exception,)):
    """健壮的错误处理装饰器"""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except exceptions as e:
                print(f"函数 {func.__name__} 执行出错: {e}")
                return default_return
        return wrapper
    return decorator

# 6. 装饰器链优化
def optimized_chain(*decorators):
    """优化的装饰器链"""
    def decorator(func: Callable) -> Callable:
        # 过滤掉None装饰器
        valid_decorators = [d for d in decorators if d is not None]
        
        # 如果没有装饰器,直接返回原函数
        if not valid_decorators:
            return func
        
        # 应用装饰器链
        result = func
        for dec in reversed(valid_decorators):
            result = dec(result)
        
        return result
    return decorator

# 创建注册器实例
registry = DecoratorRegistry()

# 添加中间件
def logging_middleware(func, args, kwargs):
    print(f"中间件: 记录函数 {func.__name__} 的调用")

def timing_middleware(func, args, kwargs):
    print(f"中间件: 开始计时 {func.__name__}")

registry.add_middleware(logging_middleware)
registry.add_middleware(timing_middleware)

# 使用最佳实践装饰器
@preserve_signature
def calculate_area(length: float, width: float) -> float:
    """计算面积"""
    return length * width

@type_safe_decorator
def greet_user(name: str, age: int) -> str:
    """问候用户"""
    return f"Hello {name}, you are {age} years old"

@ConfigurableDecorator(enabled=True, log_level="DEBUG", include_args=True)
def process_data(data: list) -> int:
    """处理数据"""
    return len(data)

@registry.register("math_operation")
def multiply(x: int, y: int) -> int:
    """乘法运算"""
    return x * y

@robust_decorator(default_return=0, exceptions=(ValueError, TypeError))
def safe_division(a: float, b: float) -> float:
    """安全除法"""
    return a / b

# 装饰器链示例
@optimized_chain(
    preserve_signature,
    ConfigurableDecorator(enabled=True, log_level="INFO"),
    robust_decorator(default_return="error")
)
def complex_operation(x: int, y: int) -> str:
    """复杂操作"""
    if x < 0 or y < 0:
        raise ValueError("参数不能为负数")
    return f"结果: {x + y}"

# 演示最佳实践
print("\n=== 装饰器最佳实践演示 ===")

print("\n1. 保持函数签名:")
result = calculate_area(5.0, 3.0)
print(f"面积: {result}")
print(f"函数签名: {inspect.signature(calculate_area)}")

print("\n2. 类型安全装饰器:")
result = greet_user("张三", 25)
print(f"问候: {result}")

print("\n3. 可配置装饰器:")
result = process_data([1, 2, 3, 4, 5])
print(f"数据长度: {result}")

print("\n4. 注册器模式:")
result = multiply(6, 7)
print(f"乘法结果: {result}")
print(f"注册的函数: {registry.list_functions()}")

print("\n5. 错误处理装饰器:")
result1 = safe_division(10, 2)
print(f"正常除法: {result1}")
result2 = safe_division(10, 0)  # 除零错误
print(f"除零结果: {result2}")

print("\n6. 装饰器链:")
 result1 = complex_operation(5, 3)
 print(f"正常操作: {result1}")
 result2 = complex_operation(-1, 2)  # 触发异常
 print(f"异常操作: {result2}")

实践练习

练习1:API限流系统

创建一个完整的API限流系统,包含多种限流策略。

# 练习1:API限流系统
print("\n=== 练习1:API限流系统 ===")

import time
import functools
from typing import Dict, Callable, Optional
from collections import defaultdict, deque
from datetime import datetime, timedelta

class RateLimiter:
    """限流器基类"""
    
    def __init__(self, max_requests: int, time_window: int):
        self.max_requests = max_requests
        self.time_window = time_window
    
    def is_allowed(self, key: str) -> bool:
        """检查是否允许请求"""
        raise NotImplementedError
    
    def reset(self, key: str = None):
        """重置限流器"""
        raise NotImplementedError

class TokenBucketLimiter(RateLimiter):
    """令牌桶限流器"""
    
    def __init__(self, max_requests: int, time_window: int, refill_rate: float = None):
        super().__init__(max_requests, time_window)
        self.refill_rate = refill_rate or max_requests / time_window
        self.buckets: Dict[str, Dict] = defaultdict(lambda: {
            'tokens': max_requests,
            'last_refill': time.time()
        })
    
    def is_allowed(self, key: str) -> bool:
        bucket = self.buckets[key]
        current_time = time.time()
        
        # 计算需要添加的令牌数
        time_passed = current_time - bucket['last_refill']
        tokens_to_add = time_passed * self.refill_rate
        
        # 更新令牌数(不超过最大值)
        bucket['tokens'] = min(self.max_requests, bucket['tokens'] + tokens_to_add)
        bucket['last_refill'] = current_time
        
        # 检查是否有可用令牌
        if bucket['tokens'] >= 1:
            bucket['tokens'] -= 1
            return True
        
        return False
    
    def reset(self, key: str = None):
        if key:
            if key in self.buckets:
                del self.buckets[key]
        else:
            self.buckets.clear()

class SlidingWindowLimiter(RateLimiter):
    """滑动窗口限流器"""
    
    def __init__(self, max_requests: int, time_window: int):
        super().__init__(max_requests, time_window)
        self.windows: Dict[str, deque] = defaultdict(deque)
    
    def is_allowed(self, key: str) -> bool:
        current_time = time.time()
        window = self.windows[key]
        
        # 清理过期的请求记录
        while window and current_time - window[0] > self.time_window:
            window.popleft()
        
        # 检查是否超过限制
        if len(window) < self.max_requests:
            window.append(current_time)
            return True
        
        return False
    
    def reset(self, key: str = None):
        if key:
            if key in self.windows:
                del self.windows[key]
        else:
            self.windows.clear()

class FixedWindowLimiter(RateLimiter):
    """固定窗口限流器"""
    
    def __init__(self, max_requests: int, time_window: int):
        super().__init__(max_requests, time_window)
        self.windows: Dict[str, Dict] = defaultdict(lambda: {
            'count': 0,
            'window_start': time.time()
        })
    
    def is_allowed(self, key: str) -> bool:
        current_time = time.time()
        window = self.windows[key]
        
        # 检查是否需要重置窗口
        if current_time - window['window_start'] > self.time_window:
            window['count'] = 0
            window['window_start'] = current_time
        
        # 检查是否超过限制
        if window['count'] < self.max_requests:
            window['count'] += 1
            return True
        
        return False
    
    def reset(self, key: str = None):
        if key:
            if key in self.windows:
                del self.windows[key]
        else:
            self.windows.clear()

# 限流装饰器
def rate_limit(limiter: RateLimiter, key_func: Callable = None, 
               error_message: str = "Rate limit exceeded"):
    """限流装饰器"""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 生成限流键
            if key_func:
                key = key_func(*args, **kwargs)
            else:
                # 默认使用函数名作为键
                key = func.__name__
            
            # 检查限流
            if not limiter.is_allowed(key):
                raise Exception(f"{error_message}: {key}")
            
            return func(*args, **kwargs)
        
        # 添加限流器管理方法
        wrapper.reset_limit = lambda k=None: limiter.reset(k)
        wrapper.limiter = limiter
        
        return wrapper
    return decorator

# 多级限流装饰器
def multi_level_rate_limit(*limiters_and_keys):
    """多级限流装饰器"""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 检查所有限流器
            for limiter, key_func, error_msg in limiters_and_keys:
                key = key_func(*args, **kwargs) if key_func else func.__name__
                
                if not limiter.is_allowed(key):
                    raise Exception(f"{error_msg}: {key}")
            
            return func(*args, **kwargs)
        return wrapper
    return decorator

# 创建不同类型的限流器
token_bucket = TokenBucketLimiter(max_requests=5, time_window=10, refill_rate=0.5)
sliding_window = SlidingWindowLimiter(max_requests=3, time_window=5)
fixed_window = FixedWindowLimiter(max_requests=10, time_window=60)

# 用户键生成函数
def user_key(*args, **kwargs):
    return kwargs.get('user_id', 'anonymous')

def ip_key(*args, **kwargs):
    return kwargs.get('ip_address', '127.0.0.1')

# 使用限流装饰器的API函数
@rate_limit(token_bucket, key_func=user_key, error_message="用户请求过于频繁")
def api_get_user_info(user_id: str, ip_address: str = None):
    """获取用户信息API"""
    return f"用户 {user_id} 的信息"

@rate_limit(sliding_window, key_func=ip_key, error_message="IP请求过于频繁")
def api_search(query: str, ip_address: str, user_id: str = None):
    """搜索API"""
    return f"搜索结果: {query}"

@multi_level_rate_limit(
    (token_bucket, user_key, "用户级别限流"),
    (sliding_window, ip_key, "IP级别限流")
)
def api_upload_file(file_name: str, user_id: str, ip_address: str):
    """文件上传API(多级限流)"""
    return f"文件 {file_name} 上传成功"

# 演示限流系统
print("\n=== 限流系统演示 ===")

print("\n1. 令牌桶限流演示:")
for i in range(8):
    try:
        result = api_get_user_info(user_id="user123", ip_address="192.168.1.1")
        print(f"请求 {i+1}: {result}")
    except Exception as e:
        print(f"请求 {i+1}: 被限流 - {e}")
    time.sleep(0.5)

print("\n2. 滑动窗口限流演示:")
for i in range(6):
    try:
        result = api_search(query=f"搜索{i+1}", ip_address="192.168.1.2")
        print(f"搜索 {i+1}: {result}")
    except Exception as e:
        print(f"搜索 {i+1}: 被限流 - {e}")
    time.sleep(1)

print("\n3. 多级限流演示:")
for i in range(4):
    try:
        result = api_upload_file(
            file_name=f"file{i+1}.txt",
            user_id="user456",
            ip_address="192.168.1.3"
        )
        print(f"上传 {i+1}: {result}")
    except Exception as e:
        print(f"上传 {i+1}: 被限流 - {e}")
    time.sleep(0.3)

练习2:缓存管理系统

创建一个功能完整的缓存管理系统,支持多种缓存策略和过期机制。

# 练习2:缓存管理系统
print("\n=== 练习2:缓存管理系统 ===")

import time
import functools
import threading
import pickle
import hashlib
from typing import Any, Callable, Optional, Dict, Union
from abc import ABC, abstractmethod
from collections import OrderedDict
from datetime import datetime, timedelta

class CacheBackend(ABC):
    """缓存后端抽象基类"""
    
    @abstractmethod
    def get(self, key: str) -> Optional[Any]:
        pass
    
    @abstractmethod
    def set(self, key: str, value: Any, ttl: Optional[int] = None) -> None:
        pass
    
    @abstractmethod
    def delete(self, key: str) -> bool:
        pass
    
    @abstractmethod
    def clear(self) -> None:
        pass
    
    @abstractmethod
    def exists(self, key: str) -> bool:
        pass

class MemoryCache(CacheBackend):
    """内存缓存后端"""
    
    def __init__(self, max_size: int = 1000):
        self.max_size = max_size
        self.cache: OrderedDict = OrderedDict()
        self.expiry_times: Dict[str, float] = {}
        self.lock = threading.RLock()
    
    def _is_expired(self, key: str) -> bool:
        """检查键是否过期"""
        if key not in self.expiry_times:
            return False
        return time.time() > self.expiry_times[key]
    
    def _cleanup_expired(self):
        """清理过期的键"""
        current_time = time.time()
        expired_keys = [
            key for key, expiry_time in self.expiry_times.items()
            if current_time > expiry_time
        ]
        
        for key in expired_keys:
            self.cache.pop(key, None)
            self.expiry_times.pop(key, None)
    
    def get(self, key: str) -> Optional[Any]:
        with self.lock:
            if key not in self.cache:
                return None
            
            if self._is_expired(key):
                self.delete(key)
                return None
            
            # LRU: 移动到末尾
            self.cache.move_to_end(key)
            return self.cache[key]
    
    def set(self, key: str, value: Any, ttl: Optional[int] = None) -> None:
        with self.lock:
            # 清理过期项
            self._cleanup_expired()
            
            # 如果缓存已满,移除最久未使用的项
            if len(self.cache) >= self.max_size and key not in self.cache:
                oldest_key = next(iter(self.cache))
                self.delete(oldest_key)
            
            self.cache[key] = value
            self.cache.move_to_end(key)
            
            # 设置过期时间
            if ttl is not None:
                self.expiry_times[key] = time.time() + ttl
            elif key in self.expiry_times:
                del self.expiry_times[key]
    
    def delete(self, key: str) -> bool:
        with self.lock:
            existed = key in self.cache
            self.cache.pop(key, None)
            self.expiry_times.pop(key, None)
            return existed
    
    def clear(self) -> None:
        with self.lock:
            self.cache.clear()
            self.expiry_times.clear()
    
    def exists(self, key: str) -> bool:
        with self.lock:
            if key not in self.cache:
                return False
            
            if self._is_expired(key):
                self.delete(key)
                return False
            
            return True
    
    def info(self) -> Dict[str, Any]:
        """获取缓存信息"""
        with self.lock:
            self._cleanup_expired()
            return {
                "size": len(self.cache),
                "max_size": self.max_size,
                "hit_rate": "N/A",  # 可以添加命中率统计
                "expired_keys": len([k for k in self.expiry_times.keys() if self._is_expired(k)])
            }

class CacheManager:
    """缓存管理器"""
    
    def __init__(self, backend: CacheBackend):
        self.backend = backend
        self.stats = {
            "hits": 0,
            "misses": 0,
            "sets": 0,
            "deletes": 0
        }
    
    def _make_key(self, func: Callable, args: tuple, kwargs: dict) -> str:
        """生成缓存键"""
        # 创建唯一的缓存键
        key_parts = [
            func.__module__,
            func.__name__,
            str(args),
            str(sorted(kwargs.items()))
        ]
        key_string = "|".join(key_parts)
        return hashlib.md5(key_string.encode()).hexdigest()
    
    def get_stats(self) -> Dict[str, Any]:
        """获取缓存统计信息"""
        total_requests = self.stats["hits"] + self.stats["misses"]
        hit_rate = self.stats["hits"] / total_requests if total_requests > 0 else 0
        
        return {
            **self.stats,
            "total_requests": total_requests,
            "hit_rate": f"{hit_rate:.2%}"
        }
    
    def cache_result(self, ttl: Optional[int] = None, 
                    key_func: Optional[Callable] = None,
                    condition: Optional[Callable] = None):
        """缓存结果装饰器"""
        def decorator(func: Callable) -> Callable:
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                # 检查缓存条件
                if condition and not condition(*args, **kwargs):
                    return func(*args, **kwargs)
                
                # 生成缓存键
                if key_func:
                    cache_key = key_func(*args, **kwargs)
                else:
                    cache_key = self._make_key(func, args, kwargs)
                
                # 尝试从缓存获取
                cached_result = self.backend.get(cache_key)
                if cached_result is not None:
                    self.stats["hits"] += 1
                    return cached_result
                
                # 缓存未命中,执行函数
                self.stats["misses"] += 1
                result = func(*args, **kwargs)
                
                # 存储到缓存
                self.backend.set(cache_key, result, ttl)
                self.stats["sets"] += 1
                
                return result
            
            # 添加缓存管理方法
            wrapper.cache_clear = self.backend.clear
            wrapper.cache_info = self.get_stats
            wrapper.cache_delete = lambda *args, **kwargs: self._delete_cache_key(
                func, args, kwargs, key_func
            )
            
            return wrapper
        return decorator
    
    def _delete_cache_key(self, func: Callable, args: tuple, kwargs: dict, 
                         key_func: Optional[Callable]):
        """删除特定的缓存键"""
        if key_func:
            cache_key = key_func(*args, **kwargs)
        else:
            cache_key = self._make_key(func, args, kwargs)
        
        if self.backend.delete(cache_key):
            self.stats["deletes"] += 1
            return True
        return False

# 创建缓存管理器
memory_backend = MemoryCache(max_size=100)
cache_manager = CacheManager(memory_backend)

# 缓存条件函数
def cache_expensive_only(*args, **kwargs):
    """只缓存耗时操作"""
    return kwargs.get('expensive', False)

def user_cache_key(*args, **kwargs):
    """用户相关的缓存键"""
    return f"user_{kwargs.get('user_id', 'anonymous')}"

# 使用缓存装饰器的函数
@cache_manager.cache_result(ttl=30)
def calculate_fibonacci(n: int) -> int:
    """计算斐波那契数(缓存30秒)"""
    print(f"计算 fibonacci({n})")
    if n <= 1:
        return n
    return calculate_fibonacci(n - 1) + calculate_fibonacci(n - 2)

@cache_manager.cache_result(ttl=60, key_func=user_cache_key)
def get_user_profile(user_id: str, include_details: bool = False) -> Dict[str, Any]:
    """获取用户资料(按用户ID缓存)"""
    print(f"从数据库加载用户 {user_id} 的资料")
    time.sleep(0.1)  # 模拟数据库查询
    
    profile = {
        "user_id": user_id,
        "name": f"用户{user_id}",
        "email": f"user{user_id}@example.com"
    }
    
    if include_details:
        profile["details"] = {"last_login": datetime.now().isoformat()}
    
    return profile

@cache_manager.cache_result(
    ttl=120, 
    condition=cache_expensive_only
)
def process_data(data: list, expensive: bool = False) -> Dict[str, Any]:
    """处理数据(只缓存标记为耗时的操作)"""
    print(f"处理数据,耗时操作: {expensive}")
    
    if expensive:
        time.sleep(0.2)  # 模拟耗时操作
    
    return {
        "processed_count": len(data),
        "sum": sum(data) if data else 0,
        "avg": sum(data) / len(data) if data else 0
    }

# 演示缓存系统
print("\n=== 缓存系统演示 ===")

print("\n1. 斐波那契缓存演示:")
start_time = time.time()
result1 = calculate_fibonacci(10)
time1 = time.time() - start_time
print(f"第一次计算: {result1}, 耗时: {time1:.4f}秒")

start_time = time.time()
result2 = calculate_fibonacci(10)  # 应该使用缓存
time2 = time.time() - start_time
print(f"第二次计算: {result2}, 耗时: {time2:.4f}秒")

print("\n2. 用户资料缓存演示:")
profile1 = get_user_profile("123", include_details=True)
print(f"第一次获取: {profile1['name']}")

profile2 = get_user_profile("123", include_details=False)  # 应该使用缓存
print(f"第二次获取: {profile2['name']}")

print("\n3. 条件缓存演示:")
data = [1, 2, 3, 4, 5]

# 不缓存的操作
result1 = process_data(data, expensive=False)
print(f"快速操作结果: {result1}")

result2 = process_data(data, expensive=False)  # 不会使用缓存
print(f"再次快速操作: {result2}")

# 缓存的操作
result3 = process_data(data, expensive=True)
print(f"耗时操作结果: {result3}")

result4 = process_data(data, expensive=True)  # 应该使用缓存
print(f"再次耗时操作: {result4}")

print("\n4. 缓存统计信息:")
print(f"缓存统计: {cache_manager.get_stats()}")
print(f"后端信息: {memory_backend.info()}")

总结

核心知识点

  1. 装饰器基础

    • 装饰器的本质是高阶函数
    • @语法糖的工作原理
    • functools.wraps的重要性
  2. 装饰器类型

    • 函数装饰器:最常用的装饰器形式
    • 类装饰器:使用类实现的装饰器
    • 属性装饰器:@property@staticmethod@classmethod
  3. 高级特性

    • 带参数的装饰器(装饰器工厂)
    • 装饰器链的执行顺序
    • 装饰器的组合和条件应用
  4. 实际应用

    • Web框架中的路由、认证、缓存
    • 数据库操作的事务管理
    • 性能监控和日志记录
    • API限流和权限控制

技能掌握

初级技能

  • 理解装饰器的基本概念和语法
  • 能够使用内置装饰器(@property@staticmethod等)
  • 编写简单的函数装饰器

中级技能

  • 创建带参数的装饰器
  • 使用类实现装饰器
  • 理解装饰器链的执行顺序
  • 在实际项目中应用装饰器

高级技能

  • 设计复杂的装饰器系统
  • 优化装饰器性能
  • 创建可配置和可组合的装饰器
  • 解决装饰器相关的设计问题

最佳实践

  1. 设计原则

    • 单一职责:每个装饰器只做一件事
    • 可组合性:装饰器应该能够安全地组合使用
    • 透明性:装饰器不应该改变函数的基本行为
  2. 性能考虑

    • 避免在装饰器中进行重复的昂贵操作
    • 使用条件装饰器避免不必要的开销
    • 合理使用缓存减少重复计算
  3. 错误处理

    • 在装饰器中妥善处理异常
    • 提供清晰的错误信息
    • 考虑装饰器失败时的回退策略
  4. 可维护性

    • 使用functools.wraps保留函数元信息
    • 提供清晰的文档和示例
    • 设计可配置的装饰器参数

常见陷阱

  1. 函数元信息丢失

    • 忘记使用@functools.wraps
    • 函数签名信息不完整
  2. 装饰器顺序问题

    • 不理解装饰器链的执行顺序
    • 装饰器之间的依赖关系处理不当
  3. 性能问题

    • 装饰器中的重复计算
    • 不必要的装饰器开销
  4. 作用域和闭包问题

    • 在循环中创建装饰器的变量捕获问题
    • 装饰器参数的作用域混乱

性能考虑

  1. 装饰器开销

    • 每次函数调用都会经过装饰器
    • 复杂的装饰器会增加调用开销
    • 使用条件装饰器在不需要时避免开销
  2. 内存使用

    • 装饰器可能会增加内存使用
    • 缓存装饰器需要考虑内存限制
    • 及时清理不需要的缓存数据
  3. 优化策略

    • 使用轻量级装饰器
    • 避免在装饰器中进行IO操作
    • 合理设计缓存策略

下一步学习

  1. 深入学习

    • 研究Python标准库中的装饰器实现
    • 学习流行框架(Django、Flask)中的装饰器设计
    • 探索装饰器的高级应用模式
  2. 实践项目

    • 构建完整的权限管理系统
    • 实现分布式缓存装饰器
    • 创建性能监控和分析工具
  3. 相关主题

    • 元类和描述符
    • 上下文管理器
    • 异步装饰器和协程

扩展阅读

  1. 官方文档

  2. 进阶资源

    • “Effective Python” - Brett Slatkin
    • “Python Tricks” - Dan Bader
    • “Architecture Patterns with Python” - Harry Percival
  3. 开源项目

    • Django框架的装饰器实现
    • Flask框架的装饰器设计
    • Celery的任务装饰器

学习建议:装饰器是Python中非常强大的特性,建议通过大量的实践来掌握。从简单的装饰器开始,逐步学习更复杂的模式,并在实际项目中应用这些知识。

下一章节022-生成器与迭代器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lvjesus

码力充电

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值