@[toc]
Python的迭代器与生成器:懒加载与内存优化的艺术
迭代器与生成器是Python高效处理数据的核心工具,通过惰性计算(按需生成数据)大幅降低内存占用,尤其适合处理大型数据集、实时数据流等场景。本文将深入解析其原理,并通过实战案例教你灵活应用。
1. 迭代协议:__iter__与__next__
原理剖析
迭代器是实现了迭代器协议的对象,必须包含两个方法:
__iter__:返回迭代器自身(return self),使对象可被迭代。__next__:返回下一个元素,无元素时抛出StopIteration异常,终止迭代。
实战:自定义倒计时迭代器
class Countdown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
num = self.current
self.current -= 1
return num
# 使用示例
for num in Countdown(5):
print(num) # 输出:5, 4, 3, 2, 1
关键特性:
- 一次性使用:遍历结束后需重新创建迭代器。
- 内存高效:仅保存当前状态,不预加载所有数据。
💡 对比可迭代对象:
列表、字典等是可迭代对象(实现__iter__),但非迭代器(不实现__next__)。迭代器一定是可迭代对象,反之不成立。
2. 生成器:yield与生成器表达式
原理:生成器是特殊的迭代器,通过 yield 暂停函数执行,下次调用时从暂停处继续,自动保存状态。
实战1:生成器函数(动态生成斐波那契数列)
def fibonacci(limit):
a, b = 0, 1
while a < limit:
yield a
a, b = b, a + b
# 生成小于100的斐波那契数
for num in fibonacci(100):
print(num) # 0, 1, 1, 2, 3, 5, 8...
实战2:生成器表达式(内存优化版列表推导)
# 生成1千万数据的平方(内存仅128B)
squares_gen = (x**2 for x in range(10_000_000))
print(next(squares_gen)) # 0
# 对比:列表推导占用约900MB内存
squares_list = [x**2 for x in range(10_000_000)]
高级技巧:生成器交互(send 方法)
def chat_bot():
response = "Hello!"
while True:
msg = yield response # 接收外部传入的值
response = f"Received: {msg}"
bot = chat_bot()
next(bot) # 初始化生成器
print(bot.send("Hi")) # 输出:Received: Hi
3. 实战:大文件分块读取与性能优化
场景:处理100GB日志文件,避免内存溢出。
方案1:逐行读取(文本文件)
def read_large_file(path):
with open(path, "r") as f:
for line in f: # 逐行流式读取
yield line.strip()
# 统计包含"ERROR"的行数
error_lines = (line for line in read_large_file("server.log") if "ERROR" in line)
error_count = sum(1 for _ in error_lines) # 内存占用≈单行大小
方案2:分块读取(二进制文件)
def read_in_chunks(file_path, chunk_size=1024*1024): # 1MB/块
with open(file_path, "rb") as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
yield chunk
# 处理每个数据块
for chunk in read_in_chunks("large_video.mp4"):
process_chunk(chunk) # 如加密/压缩
方案3:内存映射(随机访问大文件)
import mmap
with open("large_db.bin", "r+b") as f:
with mmap.mmap(f.fileno(), 0) as mmap_obj:
# 直接操作文件内存(无需加载全文)
if mmap_obj.find(b"target_data") != -1:
print("Data found!")
性能对比:
| 方法 | 内存占用 | 适用场景 |
|---|---|---|
| 逐行读取 | 极低 | 文本文件(如日志) |
| 分块读取 | 低 | 二进制文件(如图像) |
| 内存映射 | 中 | 需随机访问的大文件 |
迭代器 vs 生成器:核心区别总结
| 特性 | 迭代器 | 生成器 |
|---|---|---|
| 实现方式 | 类中实现 __next__ | 函数使用 yield |
| 代码简洁性 | 需完整定义类 | 更简洁(自动保存状态) |
| 内存占用 | 低(仅当前状态) | 极低(动态生成) |
| 适用场景 | 自定义复杂遍历逻辑 | 惰性计算、无限序列 |
下期预告:15.Python的装饰器与元编程:代码的“魔法外衣”与“自动化工厂”
内容亮点:
- ✨ 装饰器原理:深入闭包与函数包装机制(例:
@timer统计函数耗时)。 - 🛠️ 元编程实战:动态创建类、拦截属性访问(
__getattr__)。 - 🚀 应用场景:
- API权限校验装饰器
- ORM框架的元类魔法
- 自动注册插件系统
思考题:如何用装饰器实现函数执行耗时统计?答案下期揭晓!
掌握迭代器与生成器,你已迈入Python高效编程的大门。它们像数据的“流水线”,让海量处理举重若轻 🌟。
更多技术干货欢迎关注微信公众号“科威舟的AI笔记”~
【转载须知】:转载请注明原文出处及作者信息