七、Python高级特性:迭代器、生成器与装饰器
🔄 一、迭代器协议:可迭代对象的本质
“迭代器是Python序列化访问的通用接口——将复杂的遍历逻辑简化为统一的
next()
调用。”
1. 可迭代对象 vs 迭代器
类型 | 特征 | 核心方法 |
---|---|---|
可迭代对象 | 可用for 循环遍历 | __iter__() |
迭代器 | 通过next() 逐步获取数据 | __iter__() + __next__() |
# 自定义迭代器:生成斐波那契数列
class Fibonacci:def __init__(self, n):self.n = nself.a, self.b = 0, 1self.count = 0def __iter__(self):return selfdef __next__(self):if self.count >= self.n:raise StopIteration # 终止迭代value = self.aself.a, self.b = self.b, self.a + self.bself.count += 1return value# 使用迭代器
fib = Fibonacci(5)
for num in fib:print(num) # 输出:0, 1, 1, 2, 3
2. 内置迭代工具
- **
iter()
与next()
函数**:numbers = [1, 2, 3] it = iter(numbers) print(next(it)) # 1 print(next(it)) # 2
- **
enumerate()
索引迭代**:for idx, char in enumerate("Python"):print(f"{idx}:{char}") # 0:P, 1:y...
- **
zip()
并行迭代**:names = ["Alice", "Bob"] scores = [85, 92] for name, score in zip(names, scores):print(f"{name}: {score}")
🌟 二、生成器:惰性计算的魔法
1. 生成器函数(yield
)
def countdown(n):while n > 0:yield n # 暂停并返回当前值n -= 1gen = countdown(3)
print(next(gen)) # 3
print(next(gen)) # 2
优势:
- 内存高效:逐项生成数据,不预存完整序列
- 无限序列:可表示无限流(如传感器数据流)
2. 生成器表达式
squares = (x**2 for x in range(5)) # 生成器表达式
print(list(squares)) # [0, 1, 4, 9, 16]
对比列表推导式:
- 列表推导式:
[x**2 for x in range(5)]
→ 立即生成完整列表- 生成器表达式:
(x**2 for x in range(5)
→ 惰性计算
3. 协程应用(双向通信)
def coroutine():while True:received = yield # 接收外部send()的值print(f"Received: {received}")c = coroutine()
next(c) # 启动生成器(到yield处暂停)
c.send("Hello") # 输出:Received: Hello
🎭 三、装饰器:元编程的轻量级武器
1. 基础装饰器原理
def logger(func):def wrapper(*args, **kwargs):print(f"调用函数: {func.__name__}")return func(*args, **kwargs)return wrapper@logger
def add(a, b):return a + bprint(add(2, 3)) # 输出:调用函数: add → 5
执行流程:
add = logger(add)
→ 实际调用wrapper
函数
2. 带参数的装饰器
def repeat(n): # 装饰器工厂def decorator(func):def wrapper(*args, **kwargs):for _ in range(n):func(*args, **kwargs)return wrapperreturn decorator@repeat(3)
def say_hello():print("Hello!")say_hello() # 输出3次"Hello!"
3. 类装饰器
class Timer:def __init__(self, func):self.func = funcdef __call__(self, *args, **kwargs):start = time.time()result = self.func(*args, **kwargs)print(f"耗时: {time.time() - start:.4f}s")return result@Timer
def heavy_task():time.sleep(2)heavy_task() # 输出:耗时: 2.0003s
⚡ 四、综合实战:高效数据处理管道
1. 流式日志分析器
def log_reader(file):"""生成器:逐行读取日志"""with open(file) as f:for line in f:yield line.strip()def filter_errors(logs):"""过滤错误日志"""for log in logs:if "ERROR" in log:yield logdef count_logs(logs):"""统计日志数量"""count = 0for log in logs:count += 1yield count, log# 构建处理管道
logs = log_reader("app.log")
error_logs = filter_errors(logs)
counted_errors = count_logs(error_logs)for count, error in counted_errors:print(f"错误 #{count}: {error}")
2. 函数性能监控系统
import functools
import timedef performance_monitor(prefix=""):def decorator(func):@functools.wraps(func) # 保留原函数属性def wrapper(*args, **kwargs):start = time.perf_counter()result = func(*args, **kwargs)elapsed = time.perf_counter() - startprint(f"{prefix}{func.__name__} 耗时: {elapsed:.6f}s")return resultreturn wrapperreturn decorator@performance_monitor("API:")
def fetch_data(url):time.sleep(0.5)return f"Data from {url}"fetch_data("https://api.example.com") # 输出:API:fetch_data 耗时: 0.500012s
🧠 五、避坑指南与性能优化
-
迭代器陷阱
- 单次消费:迭代器只能遍历一次(
it = iter(data)
后需重新初始化) - 无限迭代:生成器需明确终止条件(避免
while True
无退出)
- 单次消费:迭代器只能遍历一次(
-
装饰器副作用
- 元信息丢失:用
@functools.wraps
保留__name__
等属性 - 调试困难:多层装饰时用
inspect
模块追踪调用栈
- 元信息丢失:用
-
性能优化技巧
- 生成器管道:替代中间列表减少内存占用
- LRU缓存:对纯函数用
@functools.lru_cache
缓存结果 - 异步生成器:
async for
处理I/O密集型任务
💎 结语:编程范式的融合艺术
迭代器统一了遍历接口,生成器实现了惰性之美,装饰器解耦了横切关注点——三者共同构建了Python高效与优雅的基石。建议在PyCharm中创建advanced_features.py
,尝试:
- 用生成器实现素数无限序列
- 为数据库查询函数添加重试装饰器
- 组合迭代器与装饰器构建ETL数据管道
下篇预告:
《Python异步编程:协程与并发实战》——揭秘如何用asyncio
处理高并发I/O!
🔗 关联知识:
- 回顾前篇:面向对象编程:从类到元类
- 官方文档:生成器 | 装饰器
- 拓展阅读:Real Python协程指南
【本文是Python入门系列第7篇】
: 迭代器协议:__iter__
与__next__
: 生成器:yield
魔法与协程应用
: 装饰器:函数增强与元编程
: 实战案例:日志处理与性能监控
: 性能优化:惰性计算与缓存策略