跳到主要内容

Python 的迭代器和生成器有什么区别?

核心概念​

  • 可迭代对象(Iterable):实现了 __iter__() 方法,可以被 for 循环遍历,如 list、str、dict
  • 迭代器(Iterator):同时实现了 __iter__() 和 __next__() 方法,能逐个产出值
  • 生成器(Generator):迭代器的一种,用 yield 或生成器表达式创建,是迭代器的子集
可迭代对象(Iterable)
└── 迭代器(Iterator)
└── 生成器(Generator)

对比总览​

迭代器生成器
创建方式实现 __iter__ + __next__ 的类yield 函数或 () 表达式
代码量较多(需写类)极少
状态保存手动管理实例属性自动保存执行帧
值的存储可预先存储所有值惰性计算,按需产出
是否是迭代器✅✅(生成器也是迭代器)

自定义迭代器(类实现)​

class CountUp:
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
val = self.current
self.current += 1
return val

for x in CountUp(3):
print(x) # 0 1 2

等价的生成器实现​

def count_up(n):
for i in range(n):
yield i

for x in count_up(3):
print(x) # 0 1 2

同样的功能,生成器写法更简洁,且自动保存执行状态,无需手动管理 current。

关键区别详解​

1. 值的生产方式​

# 迭代器可以包装已有数据
class ListIterator:
def __init__(self, data):
self.data = data # 数据已全部在内存中
self.index = 0

def __iter__(self): return self
def __next__(self):
if self.index >= len(self.data):
raise StopIteration
val = self.data[self.index]
self.index += 1
return val

# 生成器惰性计算,不预先存储数据
def gen_range(n):
i = 0
while i < n:
yield i # 每次调用才计算下一个值
i += 1

2. 内存使用​

import sys

# 列表迭代器:列表本身占内存,迭代器只是索引指针
lst = list(range(1_000_000))
it = iter(lst)
print(sys.getsizeof(lst)) # ~8 MB(数据在列表中)
print(sys.getsizeof(it)) # ~48 字节(只存索引)

# 生成器:几乎不占额外内存
gen = (x for x in range(1_000_000))
print(sys.getsizeof(gen)) # ~112 字节

3. 能否重置​

gen = (x for x in range(3))
print(list(gen)) # [0, 1, 2]
print(list(gen)) # [] ← 生成器耗尽后无法重置

# 可迭代对象(如列表)可以重复迭代
lst = [0, 1, 2]
print(list(iter(lst))) # [0, 1, 2]
print(list(iter(lst))) # [0, 1, 2] ← 每次 iter() 产生新迭代器

验证关系​

from collections.abc import Iterator, Generator
import inspect

def my_gen():
yield 1

gen = my_gen()

print(isinstance(gen, Iterator)) # True —— 生成器是迭代器
print(isinstance(gen, Generator)) # True —— 生成器是 Generator
print(inspect.isgenerator(gen)) # True

何时选择哪种​

场景推荐
简单的惰性序列生成器表达式 ()
复杂逻辑的惰性序列生成器函数 yield
需要双向通信(.send())生成器函数
需要多种迭代行为 / 复杂状态自定义迭代器类
包装现有数据结构自定义迭代器类

总结​

  • 生成器是迭代器的子集,所有生成器都是迭代器,反之不成立
  • 生成器用 yield 自动实现迭代器协议,代码更简洁
  • 迭代器类适合需要精细控制状态或复杂行为的场景
  • 两者都是一次性的:耗尽后无法重置,需重新创建