本文目录导读:
生成器(Generator)和迭代器(Iterator)是 Python 中经常一起出现的概念,但它们有本质的区别和联系。
简单一句话总结:迭代器是一个更通用的概念,而生成器是 Python 中创建迭代器的一种最方便、最常用的方式。
下面从定义、核心区别和具体例子来详细说明。
核心区别
| 特性 | 迭代器 (Iterator) | 生成器 (Generator) |
|---|---|---|
| 定义方式 | 是一个协议/概念,任何实现了 __iter__() 和 __next__() 方法的对象都是迭代器。 |
是一个函数/表达式,它使用 yield 关键字(生成器函数)或 表达式(生成器表达式)来创建。 |
| 底层机制 | 需要手动管理状态(在类中维护一个 index 属性来记录当前位置)。 |
自动保存和恢复函数执行状态,每次 yield 相当于暂停,挂起状态;下次 __next__() 时从暂停处继续。 |
| 代码量 | 通常需要定义一个类,实现两个特殊方法,代码量较大。 | 非常简洁,通常只需要一个函数加一个 yield 就完成了。 |
| 本质 | 是一种设计模式(对象),更底层。 | 是 Python 提供的一个语法糖(函数/表达式),更高级。 |
| 是否自动拥有迭代器属性 | 必须显式实现 __iter__ 和 __next__ 才能作为迭代器。 |
自动拥有这两个方法,因此它天然就是一个迭代器。 |
详细解释与例子
什么是迭代器 (Iterator)?
迭代器是一个可以记住遍历位置的对象,它遵循迭代器协议:
__iter__():返回迭代器对象本身。__next__():返回序列中的下一个元素,如果没有更多元素,则抛出StopIteration异常。
最经典的迭代器例子: Python 内置的 iter() 函数和 for 循环内部的工作原理。
手动构建一个迭代器:
class MySquareIterator:
"""一个生成 1, 4, 9, 16... 的迭代器"""
def __init__(self, limit):
self.limit = limit
self.current = 1
def __iter__(self):
# 返回迭代器本身
return self
def __next__(self):
# 返回下一个元素
if self.current <= self.limit:
result = self.current ** 2
self.current += 1
return result
else:
# 没有更多元素时抛出异常
raise StopIteration
# 使用
squares = MySquareIterator(5)
for num in squares:
print(num) # 输出: 1, 4, 9, 16, 25
什么是生成器 (Generator)?
生成器是一种特殊的迭代器,但它不需要你手动实现 __iter__ 和 __next__,它有两种主要形式:
- 生成器函数:使用
yield关键字的普通函数,每次调用next()时,函数会执行到下一个yield并暂停。 - 生成器表达式:类似于列表推导式,但使用 而不是 ,它返回一个生成器对象,按需生成值,而不是一次性生成所有值。
用生成器函数实现上面的例子:
def my_square_generator(limit):
"""一个生成 1, 4, 9, 16... 的生成器函数"""
current = 1
while current <= limit:
yield current ** 2 # 关键:yield 暂停并返回值
current += 1
# 使用
squares = my_square_generator(5) # squares 是一个生成器对象
print(type(squares)) # <class 'generator'>
print(isinstance(squares, iter(MySquareIterator(1)).__class__)) # 它是迭代器吗? 是的,生成器是迭代器
for num in squares:
print(num) # 输出: 1, 4, 9, 16, 25
生成器表达式例子:
# 列表推导式(一次性生成所有数) squares_list = [x**2 for x in range(1000000)] # 占用大量内存 # 生成器表达式(按需生成) squares_gen = (x**2 for x in range(1000000)) # 几乎不占内存,因为还没开始计算 # 需要时才一个一个取 print(next(squares_gen)) # 0 print(next(squares_gen)) # 1 print(next(squares_gen)) # 4
总结关系图
生成器 (Generator) 是一种特殊的 迭代器 (Iterator)
│
│ 是
▼
迭代器 (Iterator) 是一种可迭代对象 (Iterable) 的子集
│
│ 是
▼
可迭代对象 (Iterable): 任何可以用 for 循环遍历的对象
- 可迭代对象(Iterable):比如列表、字符串、字典、文件等,它们有
__iter__()方法,会返回一个迭代器。 - 迭代器(Iterator):
iter([1,2,3])的返回值,它既有__iter__()(返回自身),又有__next__()(逐个取值)。 - 生成器(Generator):比如使用
yield的函数或生成器表达式,它是一个语法上更简单的迭代器,并且还支持send(),close(),throw()等方法。
如何选择?
- 如果需要创建一个简单的、逐个生成值(特别是无限序列或在循环中需要维护复杂状态)的迭代器,首选生成器函数。 因为它代码更少、更易读、更不容易出错。
- 如果需要实现一个复杂的、有额外方法(不仅仅是迭代)的对象,或者需要控制比迭代更复杂的内部状态,可以考虑手动实现
__iter__和__next__来创建一个迭代器类。 但这种情况在实际工作中比较少见。 - 对于简单的、对现有可迭代对象进行转换(如取平方、过滤)的场景,用生成器表达式几乎总是最优解。 它比列表推导式更节省内存。
一句话总结:想做一个“懒加载”的遍历工具,用生成器就对了,它是 Python 迭代器模式的“完善”实现。
标签: 迭代器