跳转至

迭代器与生成器

在 Python 中,迭代器(Iterator)和生成器(Generator)是处理数据流的核心工具。它们允许我们以惰性(Lazy)的方式处理数据,即一次只处理一个数据项,而不是将整个数据集加载到内存中。这通过节省内存提高了处理大数据集的效率。

1. 迭代器 (Iterator)

迭代器是一个可以记住遍历位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

可迭代对象 (Iterable) vs 迭代器 (Iterator)

  • 可迭代对象 (Iterable): 可以直接作用于 for 循环的对象统称为可迭代对象,如 list, tuple, dict, set, str 等。
  • 迭代器 (Iterator): 可以被 next() 函数调用并不断返回下一个值的对象称为迭代器。

创建和使用迭代器

使用 iter() 函数可以将可迭代对象转换成迭代器。

# 列表是可迭代对象
my_list = [1, 2, 3]

# 创建迭代器
my_iter = iter(my_list)

# 使用 next() 获取元素
print(next(my_iter))  # 输出: 1
print(next(my_iter))  # 输出: 2
print(next(my_iter))  # 输出: 3

#再次调用会抛出 StopIteration 异常
# print(next(my_iter)) 

关于内存节省的说明

你可能注意到了,上面的例子并没有节省内存,因为列表 [1, 2, 3] 已经完整地存在于内存中了。

迭代器真正节省内存的威力在于惰性求值(Lazy Evaluation):通常我们可以直接通过算法生成数据,或者从文件流中逐行读取,而不需要先创建一个完整的列表。下面的“自定义迭代器”和“生成器”章节将展示这种“用一个生成一个”的高效用法。

自定义迭代器

要创建一个自定义迭代器,需要在类中实现 __iter__()__next__() 方法。

class MyNumbers:
    def __iter__(self):
        self.a = 1
        return self

    def __next__(self):
        if self.a <= 5:
            x = self.a
            self.a += 1
            return x
        else:
            raise StopIteration

myclass = MyNumbers()
myiter = iter(myclass)

for x in myiter:
    print(x)

2. 生成器 (Generator)

生成器是一种特殊的迭代器,它比自定义迭代器更加简洁优雅。生成器函数使用 yield 语句返回数据。

生成器函数

当一个函数包含 yield 关键字时,它就不再是一个普通的函数,而是一个生成器函数。调用生成器函数会返回一个生成器对象。

def my_generator():
    yield 1
    yield 2
    yield 3

gen = my_generator()

print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3

执行流程

  1. 调用生成器函数创建生成器对象。
  2. 调用 next() 时,函数开始执行,直到遇到 yield
  3. yield 返回一个值,并暂停函数的执行,保存当前状态(变量值、指令指针等)。
  4. 再次调用 next() 时,函数从上次暂停的地方恢复执行。

示例:斐波那契数列

使用生成器生成斐波那契数列,可以无限生成而不会占用大量内存。

def fibonacci(n):
    a, b = 0, 1
    counter = 0
    while counter < n:
        yield a
        a, b = b, a + b
        counter += 1

f = fibonacci(10)
for x in f:
    print(x, end=" ")
# 输出: 0 1 1 2 3 5 8 13 21 34

3. 迭代器 vs 生成器 vs 列表

特性 列表 (List) 迭代器 (Iterator) 生成器 (Generator)
内存占用 高 (存储所有元素) 低 (仅保存状态) 低 (仅保存状态)
访问方式 索引访问,切片 next() 逐个访问 next() 逐个访问
实现难度 最简单 需实现类方法 简单 (yield 函数)
使用场景 数据量小,需多次访问 自定义遍历逻辑 数据流处理,大数据量

总结

  • 凡是可用于 for 循环的对象都是 Iterable
  • 凡是可用于 next() 函数的对象都是 Iterator
  • 生成器是一种实现迭代器的便捷方式,推荐优先使用。
  • 在处理大量数据或无限序列时,使用迭代器和生成器可以显著节省内存。

下一步

生成器虽然强大,但也需要妥善管理。在 Python 中,有一种更通用的“资源管理”神器,常用于文件操作和数据库连接。

👉 前往下一章:上下文管理器 (Context Manager)与 with 语句