
本文将详细介绍如何将一个生成器分割成多个指定大小的子生成器,并丢弃末尾不足指定大小的剩余元素。这种方法在处理大型数据集或需要分批处理数据时非常有用,尤其是在计算元素代价高昂且不希望预先遍历整个生成器的情况下。
实现的核心思想是利用 zip 函数和迭代器的特性。 zip(*[it]*n) 表达式可以从迭代器 it 中每次读取 n 个值,并将它们打包成一个元组。当迭代器中剩余的值少于 n 个时,zip 函数会停止迭代,从而有效地丢弃了这些剩余元素。
以下是一个示例代码:
def split_generator(it, n):
"""
将生成器 it 分割成大小为 n 的子生成器,并丢弃剩余元素。
Args:
it: 要分割的生成器。
n: 每个子生成器的大小。
Yields:
包含 n 个元素的元组,表示一个子生成器。
"""
yield from zip(*[it]*n)
# 示例用法
def my_generator(limit):
for i in range(limit):
yield i
# 创建一个生成器,包含 17 个元素
my_gen = my_generator(17)
# 将生成器分割成大小为 5 的子生成器
for chunk in split_generator(my_gen, 5):
print(chunk)
# 输出:
# (0, 1, 2, 3, 4)
# (5, 6, 7, 8, 9)
# (10, 11, 12, 13, 14)代码解释:
- split_generator(it, n) 函数接受一个生成器 it 和一个整数 n 作为参数,其中 n 表示每个子生成器的大小。
- zip(*[it]*n) 表达式创建了一个迭代器,它每次从生成器 it 中读取 n 个值,并将它们打包成一个元组。
- yield from 语句将 zip 表达式返回的迭代器中的每个元组依次产生(yield)。
注意事项:
- 读取提前量: 这种方法不可避免地需要读取一些“提前量”。为了确定最后一个chunk是否完整,必须至少读取一个完整的chunk。
- 内存占用: 虽然这种方法避免了将整个生成器加载到内存中,但 zip 函数仍然需要在内存中保存 n 个元素才能创建一个元组。因此,对于非常大的 n 值,可能会增加内存占用。
- 适用场景: 这种方法适用于需要将生成器分割成固定大小的块,并且可以接受丢弃末尾剩余元素的情况。
总结:
通过使用 zip(*[it]*n) 方法,我们可以高效地将一个生成器分割成指定大小的子生成器,并丢弃剩余元素。这种方法避免了预先遍历生成器,从而节省了内存和计算资源。然而,需要注意的是,这种方法不可避免地需要读取一些“提前量”,并且对于非常大的 n 值,可能会增加内存占用。在选择这种方法时,需要根据具体的应用场景进行权衡。










