「程序类软件工具合集」
链接:https://pan.quark.cn/s/0b6102d9a66a
在Python中处理数据时,我们常遇到这样的场景:需要逐个访问百万级数字、读取GB级日志文件,或生成无限序列(如斐波那契数列)。若用列表存储所有数据,内存可能瞬间爆满;若用普通函数一次性计算所有结果,程序可能卡顿甚至崩溃。此时,迭代器和生成器便成为解决内存与性能问题的关键工具。
迭代(Iteration)是访问集合元素的标准化方式。无论是列表、字典还是字符串,Python都支持通过for
循环逐个访问元素。这种能力并非所有对象天生具备,只有实现了“可迭代协议”(Iterable Protocol)的对象才能被迭代。
示例:
my_list = [1, 2, 3]
for num in my_list:
print(num) # 输出:1 2 3
迭代器(Iterator)是实现了“迭代器协议”(Iterator Protocol)的对象,需满足两个核心方法:
__iter__()
:返回迭代器自身(return self
)。__next__()
:返回下一个元素,无元素时抛出StopIteration
异常。手动实现迭代器:
class NumberIterator:
def __init__(self, max_num):
self.max_num = max_num
self.current = 1
def __iter__(self):
return self
def __next__(self):
if self.current > self.max_num:
raise StopIteration
num = self.current
self.current += 1
return num
# 使用迭代器
num_iter = NumberIterator(3)
print(next(num_iter)) # 输出:1
print(next(num_iter)) # 输出:2
for num in num_iter: # 继续遍历剩余元素
print(num) # 输出:3
yield
替代手动实现生成器(Generator)是迭代器的“语法糖”,通过yield
关键字自动实现迭代器协议,无需手动编写__iter__
和__next__
。其核心特性是“惰性计算”(Lazy Evaluation):仅在需要时生成值,生成后暂停,下次调用时从暂停处继续。
生成器函数示例:
def number_generator(max_num):
current = 1
while current <= max_num:
yield current # 暂停并返回值
current += 1
# 使用生成器
num_gen = number_generator(3)
print(next(num_gen)) # 输出:1
print(next(num_gen)) # 输出:2
for num in num_gen: # 继续遍历剩余元素
print(num) # 输出:3
生成器表达式(类似列表推导式,但用圆括号):
gen_expr = (x for x in range(1, 4))
for num in gen_expr:
print(num) # 输出:1 2 3
__iter__
和__next__
,逻辑复杂但控制灵活。yield
自动管理状态,代码简洁易读。对比:读取日志文件
class LogIterator:
def __init__(self, file_path):
self.file_path = file_path
self.file = None
def __iter__(self):
self.file = open(self.file_path, 'r')
return self
def __next__(self):
line = self.file.readline()
if not line:
self.file.close()
raise StopIteration
return line.strip()
def log_generator(file_path):
with open(file_path, 'r') as f: # 自动关闭文件
for line in f:
yield line.strip()
测试:生成100万个数字
# 列表实现(内存爆炸)
big_list = [x for x in range(1, 1000001)] # 占用大量内存
# 生成器实现(内存友好)
def big_generator():
for x in range(1, 1000001):
yield x
gen = big_generator() # 内存占用极低
__next__
中手动记录状态(如当前位置、循环条件)。yield
自动保存局部变量和执行位置,减少出错风险。对比:生成斐波那契数列
class FibonacciIterator:
def __init__(self, max_count):
self.max_count = max_count
self.count = 0
self.a, self.b = 0, 1
def __iter__(self):
return self
def __next__(self):
if self.count >= self.max_count:
raise StopIteration
result = self.a
self.a, self.b = self.b, self.a + self.b
self.count += 1
return result
def fibonacci_generator(max_count):
a, b = 0, 1
for _ in range(max_count):
yield a
a, b = b, a + b
生成器通过惰性计算避免预加载数据,内存占用仅与当前状态相关。例如,读取1GB日志文件时:
对于小型数据集,迭代器可能因无需函数调用开销而略快。但差异通常可忽略,生成器的简洁性远胜于微小性能损失。
测试:生成1000个数字
import time
# 迭代器实现
class RangeIterator:
def __init__(self, n):
self.n = n
self.current = 0
def __iter__(self):
return self
def __next__(self):
if self.current >= self.n:
raise StopIteration
num = self.current
self.current += 1
return num
# 生成器实现
def range_generator(n):
for x in range(n):
yield x
# 测试迭代器
start = time.time()
iter_obj = RangeIterator(1000)
list(iter_obj) # 强制迭代
print(f"迭代器耗时: {time.time() - start:.6f}秒")
# 测试生成器
start = time.time()
gen_obj = range_generator(1000)
list(gen_obj) # 强制迭代
print(f"生成器耗时: {time.time() - start:.6f}秒")
结果:两者耗时接近(通常生成器略慢,但差异在毫秒级)。
生成器通过yield
将逻辑分解为步骤,代码更易读。例如,实现一个交互式生成器:
def interactive_gen():
total = 0
while True:
value = yield total # 接收外部输入并返回当前总和
if value is None:
break
total += value
gen = interactive_gen()
next(gen) # 启动生成器
print(gen.send(5)) # 输出: 5
print(gen.send(3)) # 输出: 8
结合多个生成器实现类似Unix管道的功能:
def read_logs(file_path):
with open(file_path) as f:
for line in f:
yield line.strip()
def filter_errors(lines):
for line in lines:
if "ERROR" in line:
yield line
def extract_timestamps(lines):
for line in lines:
# 假设时间戳在行首
yield line.split()[0]
# 构建管道
pipeline = extract_timestamps(filter_errors(read_logs("app.log")))
for timestamp in pipeline:
print(timestamp)
yield from
简化嵌套生成器的代码:
def flatten(nested_list):
for sublist in nested_list:
yield from sublist # 等价于 for item in sublist: yield item
nested = [[1, 2], [3, 4], [5, 6]]
for num in flatten(nested):
print(num) # 输出:1 2 3 4 5 6
结合async/await
实现异步数据流:
async def async_generator():
for i in range(3):
await asyncio.sleep(1) # 模拟异步操作
yield i
async def main():
async for num in async_generator():
print(num)
import asyncio
asyncio.run(main()) # 输出:0(1秒后)1(2秒后)2
特性 | 迭代器 | 生成器 |
---|---|---|
实现方式 | 类,手动实现__iter__和__next__ | 函数或表达式,使用yield |
内存效率 | 依赖实现(可能高或低) | 极高(惰性计算) |
状态管理 | 需手动记录 | 自动保存 |
代码复杂度 | 较高 | 极低 |
适用场景 | 复杂遍历逻辑、小型数据集 | 大数据流、无限序列、简化代码 |
行动建议:
yield from
)或构建管道处理复杂逻辑。无论是迭代器还是生成器,它们的核心目标都是“按需生成数据”,避免不必要的内存占用。理解它们的区别与联系,能让你在Python编程中写出更高效、更优雅的代码。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。