Python 生成器与迭代器详解

16 阅读5分钟

Python 生成器与迭代器详解

迭代器(Iterator)和生成器(Generator)是 Python 中处理可迭代对象的核心机制,核心价值是惰性计算用到数据时才生成,不占用大量内存,特别适合处理大数据、无限序列等场景。

先理清核心关系: 可迭代对象 → 迭代器 → 生成器

  • 生成器是特殊的迭代器
  • 迭代器是可迭代对象的一种实现。

一、基础概念

1. 可迭代对象(Iterable)

所有能被 for 循环遍历的对象都是可迭代对象,比如:列表、字符串、元组、字典、集合等。 判断标准:对象实现了 __iter__() 方法,调用后能返回一个迭代器

# 列表是可迭代对象
lst = [1, 2, 3]
print(hasattr(lst, '__iter__'))  # True

2. 迭代器(Iterator)

迭代器是实现了迭代协议的对象,必须同时实现两个方法:

  1. __iter__():返回迭代器自身
  2. __next__():返回下一个数据,无数据时抛出 StopIteration 异常

迭代器的特点:

  • 惰性计算:不一次性生成所有数据,节省内存
  • 一次性使用:遍历完就失效,无法重复遍历
  • 只能向后遍历,不能回退

二、迭代器的手动实现与使用

1. 把可迭代对象转为迭代器

iter() 函数(内置函数,本质调用 __iter__()):

lst = [1, 2, 3]
# 转为迭代器
it = iter(lst)  

# 手动获取下一个元素(调用 __next__())
print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
# print(next(it))  # 抛出 StopIteration 异常

2. for 循环的本质

for 循环会自动调用 iter()next(),并自动捕获异常:

# 底层逻辑
it = iter(lst)
while True:
    try:
        x = next(it)
        print(x)
    except StopIteration:
        break

3. 自定义迭代器类

通过类实现迭代协议,演示一个生成 1~n 整数的迭代器:

class MyIterator:
    def __init__(self, end):
        self.end = end
        self.current = 1  # 记录当前位置

    # 必须实现:返回迭代器自身
    def __iter__(self):
        return self

    # 必须实现:返回下一个值
    def __next__(self):
        if self.current > self.end:
            raise StopIteration  # 无数据时抛出异常
        value = self.current
        self.current += 1
        return value

# 使用自定义迭代器
it = MyIterator(3)
for num in it:
    print(num)  # 输出 1,2,3

三、生成器(Generator)

生成器是简化版的迭代器,无需手动写类、实现 __iter____next__,Python 自动帮我们完成。

生成器有两种写法:

  1. 生成器函数(带 yield 关键字)
  2. 生成器表达式(简洁语法)

1. 生成器函数(核心)

普通函数用 return 返回值,生成器函数用 yield 返回值

  • 执行到 yield 时,函数暂停执行,并返回当前值
  • 下次调用 next() 时,从暂停位置继续执行
  • 函数执行完毕,自动抛出 StopIteration
示例:生成 1~n 的整数
# 生成器函数
def my_generator(end):
    current = 1
    while current <= end:
        yield current  # 暂停并返回值,替代 return
        current += 1

# 创建生成器对象
gen = my_generator(3)

# 使用方式和迭代器完全一致
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3
# print(next(gen))  # StopIteration
核心优势:生成无限序列

迭代器/生成器可以轻松生成无限长度的数据,而列表做不到:

# 无限生成自然数
def infinite_nums():
    num = 0
    while True:
        yield num
        num += 1

gen = infinite_nums()
print(next(gen))  # 0
print(next(gen))  # 1
# 可以无限调用 next(),不会占用大量内存

2. 生成器表达式

语法和列表推导式几乎一样,只是把 [] 换成 ()

# 列表推导式(一次性生成所有数据,占内存)
lst = [x for x in range(3)]
print(lst)  # [0,1,2]

# 生成器表达式(惰性生成)
gen = (x for x in range(3))
print(gen)  # <generator object <genexpr> at 0x...>
print(next(gen))  # 0

四、生成器的高级用法

1. send() 方法:向生成器传值

send() 可以yield 表达式传递参数,实现双向通信:

def gen():
    value = 0
    while True:
        # 接收外部 send 的值
        receive = yield value  
        if receive:
            value = receive
        value += 1

g = gen()
print(next(g))   # 0 (启动生成器)
print(g.send(10))# 11 (传入10,value=10+1)
print(g.send(20))# 21

2. close() 方法:手动关闭生成器

g = my_generator(5)
next(g)
g.close()  # 关闭生成器
# next(g)  # 抛出 StopIteration

五、迭代器 vs 生成器:核心对比

特性迭代器生成器
实现方式类 + __iter__+__next__函数 + yield / 生成器表达式
代码量繁琐极简
内存占用惰性计算,省内存惰性计算,省内存(更简洁)
功能基础迭代功能包含迭代器所有功能,支持send/close
使用场景复杂自定义迭代逻辑简单惰性序列、大数据处理

一句话总结:生成器是 Python 为了简化迭代器开发提供的语法糖,日常开发优先用生成器


六、为什么要用迭代器/生成器?

核心场景:处理大数据/超大文件

如果用列表存储 1 亿个数字,会直接占满内存;但生成器/迭代器只占用固定内存

示例:读取超大文件(避免一次性加载到内存)

# 逐行读取文件,内存占用极低
def read_large_file(file_path):
    with open(file_path, 'r', encoding='utf-8') as f:
        for line in f:  # 文件对象本身就是迭代器
            yield line

七、常见误区

  1. 迭代器只能遍历一次
gen = (x for x in [1,2,3])
print(list(gen))  # [1,2,3]
print(list(gen))  # [] (已耗尽)
  1. 生成器函数调用才生成对象
# 错误:函数没调用,不是生成器
print(my_generator(3))  # <generator object ...>
# 正确:必须赋值给变量使用
gen = my_generator(3)
  1. yield 不是终止函数return 才会终止生成器。

总结

  1. 可迭代对象:能被 for 遍历,如列表、字符串;
  2. 迭代器:实现迭代协议,惰性计算、一次性遍历;
  3. 生成器yield 关键字实现的简化迭代器,开发效率更高;
  4. 核心价值:节省内存、支持无限序列、处理大数据