生成器和迭代器区别?

访客 python案例 1

本文目录导读:

  1. 核心区别
  2. 详细解释与例子
  3. 总结关系图
  4. 如何选择?

生成器(Generator)和迭代器(Iterator)是 Python 中经常一起出现的概念,但它们有本质的区别和联系。

简单一句话总结:迭代器是一个更通用的概念,而生成器是 Python 中创建迭代器的一种最方便、最常用的方式。

下面从定义、核心区别和具体例子来详细说明。

核心区别

特性 迭代器 (Iterator) 生成器 (Generator)
定义方式 是一个协议/概念,任何实现了 __iter__()__next__() 方法的对象都是迭代器。 是一个函数/表达式,它使用 yield 关键字(生成器函数)或 表达式(生成器表达式)来创建。
底层机制 需要手动管理状态(在类中维护一个 index 属性来记录当前位置)。 自动保存和恢复函数执行状态,每次 yield 相当于暂停,挂起状态;下次 __next__() 时从暂停处继续。
代码量 通常需要定义一个类,实现两个特殊方法,代码量较大。 非常简洁,通常只需要一个函数加一个 yield 就完成了。
本质 是一种设计模式(对象),更底层。 是 Python 提供的一个语法糖(函数/表达式),更高级。
是否自动拥有迭代器属性 必须显式实现 __iter____next__ 才能作为迭代器。 自动拥有这两个方法,因此它天然就是一个迭代器

详细解释与例子

什么是迭代器 (Iterator)?

迭代器是一个可以记住遍历位置的对象,它遵循迭代器协议

  1. __iter__():返回迭代器对象本身。
  2. __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__,它有两种主要形式:

  1. 生成器函数:使用 yield 关键字的普通函数,每次调用 next() 时,函数会执行到下一个 yield 并暂停。
  2. 生成器表达式:类似于列表推导式,但使用 而不是 ,它返回一个生成器对象,按需生成值,而不是一次性生成所有值。

用生成器函数实现上面的例子:

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 迭代器模式的“完善”实现。

标签: 迭代器

抱歉,评论功能暂时关闭!