🐍 Python 零基础入门系列(十)答案:闭包和装饰器实战答案讲解

📢 系列说明
这是《Python 零基础入门系列》第十篇的配套答案讲解!请先独立完成第十篇的3个实战练习,再参考答案进行核对。

📅 更新时间:2026 年 3 月 27 日

🎯 本篇内容:第十篇实战练习的完整参考答案 + 详细讲解 + 常见错误分析

⏱️ 预计阅读时间:50-60 分钟

📌 前置知识:已完成第十篇教程和实战练习

✍️ 作者:书到用时方恨少!


📋 完整目录

┌─────────────────────────────────────────────────────────────┐
│                    本篇博客内容导航                          │
├─────────────────────────────────────────────────────────────┤
│  第一部分:练习一答案 - 日志装饰器                           │
│  ├── 1. 完整参考代码                                         │
│  ├── 2. 逐行代码讲解                                         │
│  └── 3. 常见错误分析                                         │
├─────────────────────────────────────────────────────────────┤
│  第二部分:练习二答案 - 计时装饰器                           │
│  ├── 4. 完整参考代码                                         │
│  ├── 5. 逐行代码讲解                                         │
│  └── 6. 常见错误分析                                         │
├─────────────────────────────────────────────────────────────┤
│  第三部分:练习三答案 - 缓存装饰器                           │
│  ├── 7. 完整参考代码                                         │
│  ├── 8. 逐行代码讲解                                         │
│  └── 9. 常见错误分析                                         │
├─────────────────────────────────────────────────────────────┤
│  第四部分:优化建议与扩展                                    │
│  ├── 10. 代码优化建议                                        │
│  └── 11. 扩展学习方向                                        │
└─────────────────────────────────────────────────────────────┘

第一部分:练习一答案 - 日志装饰器

1. 完整参考代码

# ============================================================
# 练习一:日志装饰器 - 完整参考答案
# ============================================================

import time
from datetime import datetime
from functools import wraps


# ============================================================
# 日志级别定义
# ============================================================

LOG_LEVELS = {
    'DEBUG': 0,
    'INFO': 1,
    'WARNING': 2,
    'ERROR': 3
}


# ============================================================
# 日志装饰器
# ============================================================

def log_decorator(level="INFO", log_file=None):
    """
    日志装饰器
    
    Args:
        level: 日志级别 (DEBUG/INFO/WARNING/ERROR)
        log_file: 日志文件路径(可选,None 表示只输出到控制台)
    
    Returns:
        装饰器函数
    """
    
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 获取当前时间
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            
            # 记录开始时间
            start_time = time.time()
            
            # 准备日志信息
            log_messages = []
            log_messages.append(f"[{timestamp}] [{level}] 开始执行 {func.__name__}")
            log_messages.append(f"[{timestamp}] [{level}] 参数:args={args}, kwargs={kwargs}")
            
            try:
                # 调用原函数
                result = func(*args, **kwargs)
                
                # 记录结束时间
                end_time = time.time()
                exec_time = end_time - start_time
                
                # 记录成功日志
                log_messages.append(f"[{timestamp}] [{level}] 返回值:{result}")
                log_messages.append(f"[{timestamp}] [{level}] 执行时间:{exec_time:.4f}秒")
                log_messages.append(f"[{timestamp}] [{level}] 执行完成 {func.__name__}")
                
                # 输出日志
                _write_logs(log_messages, log_file)
                
                return result
                
            except Exception as e:
                # 记录结束时间
                end_time = time.time()
                exec_time = end_time - start_time
                
                # 记录错误日志
                error_level = "ERROR"
                log_messages.append(f"[{timestamp}] [{error_level}] 异常:{type(e).__name__}: {e}")
                log_messages.append(f"[{timestamp}] [{error_level}] 执行时间:{exec_time:.4f}秒")
                log_messages.append(f"[{timestamp}] [{error_level}] 执行失败 {func.__name__}")
                
                # 输出日志
                _write_logs(log_messages, log_file)
                
                # 重新抛出异常
                raise
        
        return wrapper
    
    return decorator


def _write_logs(messages, log_file=None):
    """
    写入日志
    
    Args:
        messages: 日志消息列表
        log_file: 日志文件路径
    """
    for message in messages:
        # 输出到控制台
        print(message)
        
        # 输出到文件
        if log_file:
            with open(log_file, 'a', encoding='utf-8') as f:
                f.write(message + '\n')


# ============================================================
# 测试代码
# ============================================================

if __name__ == "__main__":
    print("=" * 60)
    print("=== 日志装饰器测试 ===")
    print("=" * 60)
    
    # 测试 1:基础日志
    print("\n【测试 1】基础日志装饰器")
    print("-" * 60)
    
    @log_decorator()
    def add(a, b):
        """加法函数"""
        return a + b
    
    result = add(3, 5)
    print(f"最终结果:{result}")
    
    # 测试 2:不同日志级别
    print("\n【测试 2】不同日志级别")
    print("-" * 60)
    
    @log_decorator(level="DEBUG")
    def divide(a, b):
        return a / b
    
    @log_decorator(level="WARNING")
    def multiply(a, b):
        return a * b
    
    divide(10, 2)
    multiply(3, 4)
    
    # 测试 3:日志文件
    print("\n【测试 3】日志文件输出")
    print("-" * 60)
    
    @log_decorator(level="INFO", log_file="test.log")
    def greet(name):
        return f"Hello, {name}!"
    
    greet("小明")
    greet("小红")
    
    print("\n日志已写入 test.log 文件")
    
    # 测试 4:异常处理
    print("\n【测试 4】异常处理日志")
    print("-" * 60)
    
    @log_decorator(level="ERROR")
    def risky_divide(a, b):
        return a / b
    
    try:
        risky_divide(10, 0)
    except Exception as e:
        print(f"捕获异常:{e}")
    
    print("\n" + "=" * 60)
    print("=== 测试完成 ===")
    print("=" * 60)

2. 逐行代码讲解

📖 日志级别定义

LOG_LEVELS = {
    'DEBUG': 0,
    'INFO': 1,
    'WARNING': 2,
    'ERROR': 3
}

讲解

  • 定义日志级别字典,便于扩展级别过滤功能
  • 数值越小级别越低,可用于过滤日志输出

📖 装饰器结构

def log_decorator(level="INFO", log_file=None):
    """日志装饰器"""
    
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 装饰逻辑
            pass
        return wrapper
    
    return decorator

讲解

  • 三层嵌套:装饰器参数 → 装饰器 → 包装函数
  • 使用 @wraps 保留原函数信息
  • 使用 *args, **kwargs 保证通用性

📖 时间记录

timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
start_time = time.time()

# ... 执行函数 ...

end_time = time.time()
exec_time = end_time - start_time

讲解

  • datetime 用于格式化时间戳
  • time.time() 用于计算执行时间
  • 分别记录开始和结束时间

📖 异常处理

try:
    result = func(*args, **kwargs)
    # 成功日志
    return result
except Exception as e:
    # 错误日志
    raise  # 重新抛出异常

讲解

  • 使用 try-except 捕获异常
  • 记录异常信息后重新抛出,不改变原函数行为
  • 确保异常情况下也能记录日志

📖 日志写入

def _write_logs(messages, log_file=None):
    for message in messages:
        print(message)  # 控制台输出
        if log_file:
            with open(log_file, 'a', encoding='utf-8') as f:
                f.write(message + '\n')  # 文件输出

讲解

  • 支持同时输出到控制台和文件
  • 使用 a 模式追加写入,不覆盖原有内容
  • 指定 utf-8 编码,支持中文

3. 常见错误分析

❌ 错误 1:忘记使用 @wraps

# 错误写法
def log_decorator(level="INFO"):
    def decorator(func):
        def wrapper(*args, **kwargs):  # ❌ 没有 @wraps
            # ...
        return wrapper
    return decorator

# 问题:原函数名和文档丢失
print(add.__name__)  # wrapper 而不是 add

正确写法

@wraps(func)
def wrapper(*args, **kwargs):
    # ...

❌ 错误 2:异常被吞掉

# 错误写法
try:
    result = func(*args, **kwargs)
    return result
except Exception as e:
    print(f"错误:{e}")
    # ❌ 没有重新抛出异常

# 问题:调用者无法知道函数失败了

正确写法

except Exception as e:
    print(f"错误:{e}")
    raise  # ✅ 重新抛出

❌ 错误 3:文件未关闭

# 错误写法
if log_file:
    f = open(log_file, 'a')
    f.write(message + '\n')
    # ❌ 忘记关闭文件

# 问题:资源泄漏,可能导致数据丢失

正确写法

if log_file:
    with open(log_file, 'a', encoding='utf-8') as f:
        f.write(message + '\n')  # ✅ 自动关闭

❌ 错误 4:装饰器参数层级错误

# 错误写法
def log_decorator(func, level="INFO"):  # ❌ func 位置错误
    def wrapper(*args, **kwargs):
        # ...
    return wrapper

# 问题:无法作为 @log_decorator(level="INFO") 使用

正确写法

def log_decorator(level="INFO"):  # ✅ 先接收装饰器参数
    def decorator(func):  # 再接收函数
        def wrapper(*args, **kwargs):
            # ...
        return wrapper
    return decorator

第二部分:练习二答案 - 计时装饰器

4. 完整参考代码

# ============================================================
# 练习二:计时装饰器 - 完整参考答案
# ============================================================

import time
from functools import wraps
from collections import defaultdict


# ============================================================
# 方案 1:函数装饰器版本
# ============================================================

def timer_decorator(threshold=0.1, log_stats=False):
    """
    计时装饰器
    
    Args:
        threshold: 阈值(秒),超过此时间发出警告
        log_stats: 是否记录统计数据
    
    Returns:
        装饰器函数
    """
    # 存储统计数据
    stats = defaultdict(lambda: {
        'count': 0,
        'total_time': 0,
        'min_time': float('inf'),
        'max_time': 0,
        'times': []
    })
    
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 开始计时
            start = time.perf_counter()
            
            # 执行函数
            result = func(*args, **kwargs)
            
            # 结束计时
            end = time.perf_counter()
            exec_time = end - start
            
            # 更新统计数据
            if log_stats:
                stats[func.__name__]['count'] += 1
                stats[func.__name__]['total_time'] += exec_time
                stats[func.__name__]['min_time'] = min(
                    stats[func.__name__]['min_time'], exec_time
                )
                stats[func.__name__]['max_time'] = max(
                    stats[func.__name__]['max_time'], exec_time
                )
                stats[func.__name__]['times'].append(exec_time)
            
            # 输出时间信息
            print(f"[{func.__name__}] 执行时间:{exec_time:.6f}秒")
            
            # 阈值警告
            if exec_time > threshold:
                print(f"⚠️  警告:{func.__name__} 执行时间超过阈值 {threshold}秒")
            
            return result
        
        # 添加统计信息访问方法
        if log_stats:
            def get_stats():
                s = stats[func.__name__]
                if s['count'] == 0:
                    return None
                return {
                    'count': s['count'],
                    'avg_time': s['total_time'] / s['count'],
                    'min_time': s['min_time'],
                    'max_time': s['max_time'],
                    'total_time': s['total_time']
                }
            wrapper.get_stats = get_stats
        
        return wrapper
    
    return decorator


# ============================================================
# 方案 2:类装饰器版本
# ============================================================

class Timer:
    """计时类装饰器"""
    
    def __init__(self, threshold=0.1, log_stats=False):
        self.threshold = threshold
        self.log_stats = log_stats
        self.stats = {}
    
    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 开始计时
            start = time.perf_counter()
            
            # 执行函数
            result = func(*args, **kwargs)
            
            # 结束计时
            end = time.perf_counter()
            exec_time = end - start
            
            # 更新统计数据
            if self.log_stats:
                if func.__name__ not in self.stats:
                    self.stats[func.__name__] = {
                        'count': 0,
                        'total_time': 0,
                        'min_time': float('inf'),
                        'max_time': 0
                    }
                
                self.stats[func.__name__]['count'] += 1
                self.stats[func.__name__]['total_time'] += exec_time
                self.stats[func.__name__]['min_time'] = min(
                    self.stats[func.__name__]['min_time'], exec_time
                )
                self.stats[func.__name__]['max_time'] = max(
                    self.stats[func.__name__]['max_time'], exec_time
                )
            
            # 输出时间信息
            print(f"[{func.__name__}] 执行时间:{exec_time:.6f}秒")
            
            # 阈值警告
            if exec_time > self.threshold:
                print(f"⚠️  警告:{func.__name__} 执行时间超过阈值 {self.threshold}秒")
            
            return result
        
        # 添加统计信息访问方法
        def get_stats(func_name=func.__name__):
            if func_name not in self.stats:
                return None
            s = self.stats[func_name]
            if s['count'] == 0:
                return None
            return {
                'count': s['count'],
                'avg_time': s['total_time'] / s['count'],
                'min_time': s['min_time'],
                'max_time': s['max_time'],
                'total_time': s['total_time']
            }
        
        wrapper.get_stats = get_stats
        wrapper.all_stats = lambda: self.stats
        
        return wrapper
    
    def print_all_stats(self):
        """打印所有函数的统计信息"""
        print("\n" + "=" * 60)
        print("所有函数性能统计")
        print("=" * 60)
        for func_name, stats in self.stats.items():
            if stats['count'] > 0:
                avg = stats['total_time'] / stats['count']
                print(f"\n{func_name}:")
                print(f"  调用次数:{stats['count']}")
                print(f"  平均时间:{avg:.6f}秒")
                print(f"  最短时间:{stats['min_time']:.6f}秒")
                print(f"  最长时间:{stats['max_time']:.6f}秒")
                print(f"  总时间:{stats['total_time']:.6f}秒")


# ============================================================
# 测试代码
# ============================================================

if __name__ == "__main__":
    print("=" * 60)
    print("=== 计时装饰器测试 ===")
    print("=" * 60)
    
    # 测试 1:基础计时
    print("\n【测试 1】基础计时装饰器")
    print("-" * 60)
    
    @timer_decorator()
    def quick_func():
        time.sleep(0.01)
        return "快速完成"
    
    quick_func()
    
    # 测试 2:阈值警告
    print("\n【测试 2】阈值警告")
    print("-" * 60)
    
    @timer_decorator(threshold=0.05)
    def slow_func():
        time.sleep(0.1)
        return "慢速完成"
    
    slow_func()
    
    # 测试 3:统计功能
    print("\n【测试 3】统计功能")
    print("-" * 60)
    
    @timer_decorator(log_stats=True)
    def repeat_func():
        time.sleep(0.02)
        return "重复执行"
    
    for i in range(5):
        repeat_func()
    
    # 获取统计信息
    stats = repeat_func.get_stats()
    print(f"\n统计信息:{stats}")
    
    # 测试 4:类装饰器
    print("\n【测试 4】类装饰器版本")
    print("-" * 60)
    
    timer = Timer(threshold=0.05, log_stats=True)
    
    @timer
    def func1():
        time.sleep(0.03)
        return "func1"
    
    @timer
    def func2():
        time.sleep(0.08)
        return "func2"
    
    func1()
    func2()
    func1()
    func2()
    
    # 打印所有统计
    timer.print_all_stats()
    
    print("\n" + "=" * 60)
    print("=== 测试完成 ===")
    print("=" * 60)

5. 逐行代码讲解

📖 精确计时

start = time.perf_counter()
# ... 执行函数 ...
end = time.perf_counter()
exec_time = end - start

讲解

  • time.perf_counter()time.time() 更精确
  • 专门用于测量短时间间隔
  • 不受系统时钟调整影响

📖 统计数据存储

stats = defaultdict(lambda: {
    'count': 0,
    'total_time': 0,
    'min_time': float('inf'),
    'max_time': 0,
    'times': []
})

讲解

  • 使用 defaultdict 自动初始化
  • 存储调用次数、总时间、最小/最大时间
  • float('inf') 确保第一次比较能更新最小值

📖 统计信息访问

def get_stats():
    s = stats[func.__name__]
    if s['count'] == 0:
        return None
    return {
        'count': s['count'],
        'avg_time': s['total_time'] / s['count'],
        'min_time': s['min_time'],
        'max_time': s['max_time'],
        'total_time': s['total_time']
    }

wrapper.get_stats = get_stats

讲解

  • 将统计方法绑定到 wrapper 函数
  • 调用 func.get_stats() 即可获取统计
  • 计算平均值、最小值、最大值

📖 类装饰器实现

class Timer:
    def __init__(self, threshold=0.1, log_stats=False):
        self.threshold = threshold
        self.log_stats = log_stats
        self.stats = {}
    
    def __call__(self, func):
        # 返回包装函数
        pass
    
    def print_all_stats(self):
        # 打印所有统计
        pass

讲解

  • 使用类保存装饰器状态
  • __call__ 使实例可调用
  • 可以管理多个被装饰函数的统计

6. 常见错误分析

❌ 错误 1:使用 time.time() 而非 perf_counter()

# 不够精确
start = time.time()
end = time.time()

# 更精确
start = time.perf_counter()  # ✅
end = time.perf_counter()

❌ 错误 2:统计数据作用域错误

# 错误写法
def timer_decorator():
    stats = {}  # ❌ 每个装饰器实例独立
    
    def decorator(func):
        def wrapper(*args, **kwargs):
            # 无法跨函数统计
            pass
        return wrapper
    return decorator

# 问题:无法统计多个函数的整体性能

正确写法:使用类装饰器或外部字典

❌ 错误 3:最小值初始化错误

# 错误写法
'min_time': 0  # ❌ 0 比任何正数都小

# 正确写法
'min_time': float('inf')  # ✅ 无穷大

❌ 错误 4:忘记绑定统计方法

# 错误写法
def decorator(func):
    def wrapper(*args, **kwargs):
        # ...
    return wrapper
    # ❌ 没有绑定 get_stats

# 正确写法
wrapper.get_stats = get_stats  # ✅
return wrapper

第三部分:练习三答案 - 缓存装饰器

7. 完整参考代码

# ============================================================
# 练习三:缓存装饰器 - 完整参考答案
# ============================================================

import time
from functools import wraps
from collections import OrderedDict


# ============================================================
# 方案 1:基础缓存装饰器
# ============================================================

def cache_decorator(max_size=128, ttl=None, key_func=None):
    """
    缓存装饰器
    
    Args:
        max_size: 最大缓存条目数
        ttl: 缓存有效期(秒),None 表示永不过期
        key_func: 自定义缓存键生成函数
    
    Returns:
        装饰器函数
    """
    # 使用 OrderedDict 实现 LRU
    cache = OrderedDict()
    # 存储过期时间
    expire_times = {}
    
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 生成缓存键
            if key_func:
                key = key_func(*args, **kwargs)
            else:
                key = (args, tuple(sorted(kwargs.items())))
            
            # 检查缓存
            current_time = time.time()
            
            if key in cache:
                # 检查是否过期
                if ttl is None or current_time - expire_times[key] < ttl:
                    # 命中缓存,移到末尾(最近使用)
                    cache.move_to_end(key)
                    print(f"[CACHE HIT] {func.__name__}({key})")
                    return cache[key]
                else:
                    # 过期,删除
                    del cache[key]
                    del expire_times[key]
            
            # 未命中,执行函数
            print(f"[CACHE MISS] {func.__name__}({key})")
            result = func(*args, **kwargs)
            
            # 存入缓存
            # 检查大小限制
            if len(cache) >= max_size:
                # 删除最久未使用的
                oldest_key = next(iter(cache))
                del cache[oldest_key]
                if oldest_key in expire_times:
                    del expire_times[oldest_key]
            
            cache[key] = result
            expire_times[key] = current_time
            
            return result
        
        # 添加缓存管理方法
        def cache_info():
            return {
                'size': len(cache),
                'max_size': max_size,
                'keys': list(cache.keys())
            }
        
        def cache_clear():
            cache.clear()
            expire_times.clear()
        
        wrapper.cache_info = cache_info
        wrapper.cache_clear = cache_clear
        
        return wrapper
    
    return decorator


# ============================================================
# 方案 2:使用 lru_cache 简化实现
# ============================================================

from functools import lru_cache

def simple_cache(max_size=128):
    """
    简单缓存装饰器(使用 lru_cache)
    """
    def decorator(func):
        return lru_cache(maxsize=max_size)(func)
    return decorator


# ============================================================
# 测试代码
# ============================================================

if __name__ == "__main__":
    print("=" * 60)
    print("=== 缓存装饰器测试 ===")
    print("=" * 60)
    
    # 测试 1:基础缓存
    print("\n【测试 1】基础缓存装饰器")
    print("-" * 60)
    
    @cache_decorator()
    def fibonacci(n):
        """计算斐波那契数列"""
        if n <= 1:
            return n
        return fibonacci(n - 1) + fibonacci(n - 2)
    
    print(f"fibonacci(10) = {fibonacci(10)}")
    print(f"fibonacci(10) 再次调用 = {fibonacci(10)}")
    print(f"缓存信息:{fibonacci.cache_info()}")
    
    # 测试 2:缓存大小限制
    print("\n【测试 2】缓存大小限制")
    print("-" * 60)
    
    @cache_decorator(max_size=3)
    def compute(x):
        time.sleep(0.01)
        return x * 2
    
    for i in range(5):
        compute(i)
    
    print(f"缓存信息:{compute.cache_info()}")
    # 应该只保留最近的 3 个
    
    # 测试 3:缓存过期
    print("\n【测试 3】缓存过期")
    print("-" * 60)
    
    @cache_decorator(ttl=2)
    def get_timestamp():
        return time.time()
    
    ts1 = get_timestamp()
    print(f"第一次:{ts1}")
    
    time.sleep(1)
    ts2 = get_timestamp()
    print(f"1 秒后:{ts2} (应该命中缓存)")
    
    time.sleep(2)
    ts3 = get_timestamp()
    print(f"3 秒后:{ts3} (应该重新计算)")
    
    # 测试 4:自定义缓存键
    print("\n【测试 4】自定义缓存键")
    print("-" * 60)
    
    def make_key(*args, **kwargs):
        # 只根据第一个参数生成键
        return args[0] if args else None
    
    @cache_decorator(key_func=make_key)
    def process(data, option='default'):
        return f"处理 {data} 使用 {option}"
    
    print(process("data1", 'opt1'))
    print(process("data1", 'opt2'))  # 应该命中缓存
    print(process("data2", 'opt1'))  # 应该重新计算
    
    # 测试 5:缓存清除
    print("\n【测试 5】缓存清除")
    print("-" * 60)
    
    @cache_decorator()
    def add(a, b):
        return a + b
    
    add(1, 2)
    add(3, 4)
    print(f"清除前:{add.cache_info()}")
    
    add.cache_clear()
    print(f"清除后:{add.cache_info()}")
    
    print("\n" + "=" * 60)
    print("=== 测试完成 ===")
    print("=" * 60)

8. 逐行代码讲解

📖 LRU 缓存实现

cache = OrderedDict()

# 存入缓存
cache[key] = result

# 移到末尾(最近使用)
cache.move_to_end(key)

# 删除最久未使用的
oldest_key = next(iter(cache))
del cache[oldest_key]

讲解

  • OrderedDict 保持插入顺序
  • move_to_end() 将键移到末尾
  • next(iter(cache)) 获取第一个键(最久未使用)

📖 缓存键生成

if key_func:
    key = key_func(*args, **kwargs)
else:
    key = (args, tuple(sorted(kwargs.items())))

讲解

  • 默认使用参数元组作为键
  • sorted(kwargs.items()) 确保关键字参数顺序一致
  • 自定义 key_func 可处理特殊情况

📖 缓存过期检查

current_time = time.time()

if key in cache:
    if ttl is None or current_time - expire_times[key] < ttl:
        # 未过期,返回缓存
        return cache[key]
    else:
        # 过期,删除
        del cache[key]

讲解

  • 存储每个键的过期时间
  • 每次访问检查是否过期
  • 过期后重新计算并更新缓存

📖 缓存管理方法

def cache_info():
    return {
        'size': len(cache),
        'max_size': max_size,
        'keys': list(cache.keys())
    }

def cache_clear():
    cache.clear()
    expire_times.clear()

wrapper.cache_info = cache_info
wrapper.cache_clear = cache_clear

讲解

  • 提供缓存状态查询方法
  • 提供手动清除缓存方法
  • 绑定到 wrapper 函数上

9. 常见错误分析

❌ 错误 1:使用普通字典无法实现 LRU

# 错误写法
cache = {}  # ❌ 普通字典无序(Python 3.7+ 有序但无 move_to_end)

# 正确写法
from collections import OrderedDict
cache = OrderedDict()  # ✅

❌ 错误 2:缓存键不可哈希

# 错误写法
def wrapper(*args, **kwargs):
    key = (args, kwargs)  # ❌ kwargs 是字典,不可哈希

# 正确写法
key = (args, tuple(sorted(kwargs.items())))  # ✅

❌ 错误 3:过期时间检查错误

# 错误写法
if current_time - expire_times[key] > ttl:  # ❌ 逻辑反了
    return cache[key]

# 正确写法
if current_time - expire_times[key] < ttl:  # ✅ 小于 ttl 才有效
    return cache[key]

❌ 错误 4:缓存大小检查时机错误

# 错误写法
if len(cache) >= max_size:
    del cache[oldest_key]
cache[key] = result  # ❌ 先检查再存入,会多一条

# 正确写法
if len(cache) >= max_size:
    del cache[oldest_key]
cache[key] = result  # ✅ 或者先存入再检查

第四部分:优化建议与扩展

10. 代码优化建议

📌 日志装饰器优化

# 优化 1:添加日志级别过滤
def log_decorator(level="INFO", log_file=None):
    min_level = LOG_LEVELS.get(level, 1)
    
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if LOG_LEVELS.get(level, 1) < min_level:
                return func(*args, **kwargs)  # 跳过日志
            # ...
# 优化 2:使用 logging 模块
import logging

def log_decorator(logger=None):
    if logger is None:
        logger = logging.getLogger(__name__)
    
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            logger.info(f"开始执行 {func.__name__}")
            try:
                result = func(*args, **kwargs)
                logger.info(f"执行完成 {func.__name__}")
                return result
            except Exception as e:
                logger.error(f"执行失败 {func.__name__}: {e}")
                raise
        return wrapper
    return decorator

📌 计时装饰器优化

# 优化 1:添加线程安全
import threading

class Timer:
    def __init__(self, threshold=0.1, log_stats=False):
        self.threshold = threshold
        self.log_stats = log_stats
        self.stats = {}
        self.lock = threading.Lock()  # 线程锁
    
    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            with self.lock:  # 加锁
                # 更新统计
                pass
            return result
        return wrapper
# 优化 2:添加性能报告
def print_report(self):
    import pandas as pd
    df = pd.DataFrame(self.stats).T
    df['avg_time'] = df['total_time'] / df['count']
    print(df.sort_values('avg_time', ascending=False))

📌 缓存装饰器优化

# 优化 1:添加缓存命中率统计
def cache_decorator(max_size=128, ttl=None):
    cache = OrderedDict()
    stats = {'hits': 0, 'misses': 0}
    
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            key = (args, tuple(sorted(kwargs.items())))
            if key in cache:
                stats['hits'] += 1
                # ...
            else:
                stats['misses'] += 1
                # ...
        
        def cache_stats():
            total = stats['hits'] + stats['misses']
            hit_rate = stats['hits'] / total if total > 0 else 0
            return {
                'hits': stats['hits'],
                'misses': stats['misses'],
                'hit_rate': f"{hit_rate:.2%}"
            }
        
        wrapper.cache_stats = cache_stats
        return wrapper
    return decorator

11. 扩展学习方向

┌─────────────────────────────────────────────────────────────┐
│                    扩展学习方向                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  📚 高级装饰器模式                                           │
│  ├── 装饰器链(多个装饰器组合)                             │
│  ├── 装饰器工厂(动态生成装饰器)                           │
│  └── 装饰器注册表(集中管理装饰器)                         │
│                                                             │
│  📚 性能优化                                                 │
│  ├── 异步装饰器(支持 async/await)                         │
│  ├── 装饰器性能分析                                         │
│  └── 装饰器开销优化                                         │
│                                                             │
│  📚 实际应用                                                 │
│  ├── Web 框架装饰器(Flask/Django 路由)                    │
│  ├── API 装饰器(认证、限流、缓存)                         │
│  └── 测试装饰器(pytest  fixtures)                         │
│                                                             │
│  📚 第三方库                                                 │
│  ├── functools.lru_cache                                    │
│  ├── cachetools(高级缓存)                                 │
│  └── decorator 库(简化装饰器编写)                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

📝 总结

✅ 本篇核心内容回顾

练习 核心知识点 难度 关键技能
练习一 日志装饰器 ⭐⭐⭐ 异常处理、文件操作
练习二 计时装饰器 ⭐⭐⭐⭐ 性能分析、统计计算
练习三 缓存装饰器 ⭐⭐⭐⭐⭐ LRU 算法、过期策略

💡 学习建议

┌─────────────────────────────────────────────────────────────┐
│                    学习建议                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1️⃣ 理解装饰器执行流程                                       │
│     • 装饰器参数 → 装饰器 → 包装函数                         │
│     • 从内到外装饰,从外到内执行                            │
│                                                             │
│  2️⃣ 掌握闭包变量管理                                         │
│     • 理解变量作用域                                        │
│     • 使用 nonlocal 修改外部变量                            │
│     • 注意可变对象的引用问题                                │
│                                                             │
│  3️⃣ 始终使用 @wraps                                          │
│     • 保留原函数信息                                        │
│     • 便于调试和文档生成                                    │
│                                                             │
│  4️⃣ 注意装饰器性能                                           │
│     • 装饰器本身有开销                                      │
│     • 避免在装饰器中做耗时操作                              │
│     • 缓存装饰器要合理设置大小                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘

🚀 下一步学习

完成本篇答案学习后,建议:

  1. 复习第十篇教程,巩固闭包和装饰器知识
  2. 独立完成所有练习,不要直接抄答案
  3. 尝试优化代码,添加更多功能
  4. 预习第十一篇:模块和包
  5. 在实际项目中使用装饰器,如日志、缓存、权限控制等

📅 更新时间:2026 年 3 月 27 日
✍️ 作者:书到用时方恨少! | 专注 Python 教学与AI技术分享
💌 如有疑问,欢迎在评论区留言讨论!

更多推荐