飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 第1章 Python简介

    • Python是什么
    • 安装与运行
    • 交互式解释器
    • 注释与编码规范
  • 第2章 变量与数据类型

    • 变量与对象
    • 整数 int
    • 浮点数 float
    • 复数 complex
    • 布尔值 bool
    • 字符串 str
    • 空值 None
    • 类型转换
  • 第3章 运算符与表达式

    • 算术运算符
    • 比较运算符
    • 赋值运算符
    • 逻辑运算符
    • 位运算符
    • 身份与成员运算符
    • 海象运算符
    • 运算符优先级
  • 第4章 流程控制

    • if 语句
    • if-else 语句
    • if-elif-else 语句
    • match-case 语句
    • 条件表达式(三元运算符)
    • while 循环
    • for 循环
    • range 函数
    • break 与 continue
    • 循环的 else 子句
    • pass 语句
  • 第5章 数据结构

    • 列表创建与索引
    • 列表方法
    • 列表推导式
    • 元组
    • 序列解包
    • 集合
    • 字典创建与访问
    • 字典方法
    • 字典推导式
    • range 对象
  • 第6章 函数

    • 定义函数
    • 位置参数与关键字参数
    • 默认参数
    • 可变参数
    • 解包实参
    • 函数返回值
    • lambda 表达式
    • 文档字符串与注解
    • 作用域与命名空间
    • global 与 nonlocal
  • 第7章 模块与包

    • 模块导入
    • 模块搜索路径
    • 包与相对导入
    • 标准库概览
  • 第8章 文件与输入输出

    • 文件读写
    • 上下文管理器
    • 字符串格式化
    • JSON 与 CSV
  • 第9章 面向对象

    • 类与对象
    • 方法
    • 实例变量与类变量
    • 私有变量
    • 继承
    • 多重继承
    • 魔术方法
    • 属性装饰器
    • 数据类 dataclass
  • 第10章 异常处理

    • 语法错误与异常
    • try-except
    • 异常链与 raise
    • 清理操作
    • 自定义异常
  • 第11章 迭代器与生成器

    • 迭代器协议
    • 生成器
    • 生成器表达式
    • 迭代工具
  • 第12章 高级特性

    • 装饰器
    • 函数式编程
  • 第13章 工程实践

    • 测试与调试
    • 代码质量
    • 虚拟环境

生成器

生成器是 Python 中创建迭代器的简洁而强大的工具。它的写法类似普通函数,但使用 yield 语句返回数据,并在每次产出后暂停执行,保存全部局部状态,下次从暂停处恢复。

yield 语法与生成器函数

在函数体内使用 yield 关键字,该函数就变成了生成器函数。调用生成器函数不会立即执行函数体,而是返回一个生成器对象——一种特殊的迭代器。

def reverse(data):
    """反向产出序列元素的生成器。"""
    for index in range(len(data) - 1, -1, -1):
        yield data[index]

# 调用生成器函数得到生成器对象
gen = reverse("golf")
print(type(gen))  # <class 'generator'>

# 用 for 循环消费
for char in gen:
    print(char)  # f, l, o, g

生成器对象自动实现了 __iter__() 和 __next__() 方法,因此它既是可迭代对象也是迭代器。当 __next__() 被调用时,生成器函数从上次离开的位置恢复执行,直到遇到下一个 yield 或函数结束。

def simple_gen():
    print("开始")
    yield 1
    print("恢复1")
    yield 2
    print("恢复2")
    yield 3
    print("结束")

g = simple_gen()
print(next(g))  # 开始 → 1
print(next(g))  # 恢复1 → 2
print(next(g))  # 恢复2 → 3
print(next(g))  # 结束 → StopIteration

yield 右侧的表达式值会被返回给调用者,而生成器函数的局部变量、执行位置、指令指针等全部状态都被冻结保存。这种自动状态管理让生成器比基于类的迭代器更易编写、更易读。

生成器与迭代器的关系

生成器是迭代器的一种实现方式,但比普通迭代器更强大。二者的关系可以概括为:

  • 所有生成器都是迭代器(继承自 Iterator)。
  • 生成器自动实现 __iter__() 和 __next__(),无需手动编写。
  • 生成器自动处理 StopIteration:函数正常结束时,生成器自动抛出 StopIteration。
  • 生成器支持额外的方法:send()、throw()、close()。
from collections.abc import Iterator

def gen():
    yield 1

g = gen()
print(isinstance(g, Iterator))  # True
print(iter(g) is g)             # True

send():双向通信

send(value) 方法允许调用者向生成器发送数据。生成器内部的 yield 表达式可以接收这个值,从而实现双向数据流。

def running_average():
    """实时计算移动平均值的生成器。"""
    total = 0.0
    count = 0
    average = None
    while True:
        term = yield average
        total += term
        count += 1
        average = total / count

avg = running_average()
print(next(avg))        # 必须先调用 next() 或 send(None) 启动生成器
print(avg.send(10))     # 10.0
print(avg.send(20))     # 15.0
print(avg.send(30))     # 20.0

生成器启动后停在第一个 yield average 处。avg.send(10) 将 10 赋给 term,然后继续执行直到下一个 yield。注意:首次启动生成器时只能使用 next(avg) 或 avg.send(None),因为此时没有 yield 表达式在等待接收值。

def echo():
    """回显生成器:接收什么就返回什么。"""
    while True:
        received = yield "等待输入..."
        yield f"收到:{received}"

g = echo()
print(next(g))           # 启动,输出 "等待输入..."
print(g.send("hello"))   # 输出 "收到:hello"
print(next(g))           # 再次到第一个 yield,输出 "等待输入..."
print(g.send("world"))   # 输出 "收到:world"

throw():向生成器注入异常

throw(type[, value[, traceback]]) 在生成器当前暂停的位置抛出指定异常。生成器可以在内部捕获该异常,或者让它传播出去。

def controlled_gen():
    try:
        yield "正常状态"
    except ValueError:
        yield "已处理 ValueError"
    yield "继续执行"

g = controlled_gen()
print(next(g))              # 正常状态
print(g.throw(ValueError))  # 已处理 ValueError
print(next(g))              # 继续执行

如果生成器没有捕获抛入的异常,异常会向上传播到调用者。这在需要优雅终止生成器或通知它外部状态变化时很有用。

def infinite_counter():
    n = 0
    while True:
        try:
            yield n
            n += 1
        except ZeroDivisionError:
            print("计数器被重置")
            n = 0

g = infinite_counter()
print(next(g))   # 0
print(next(g))   # 1
print(next(g))   # 2
g.throw(ZeroDivisionError)  # 计数器被重置
print(next(g))   # 0

close():终止生成器

close() 方法在生成器暂停处抛出 GeneratorExit 异常。如果生成器捕获了该异常并正常退出,close() 静默完成;如果生成器忽略该异常或产生新值,会触发 RuntimeError。

def resource_manager():
    print("资源初始化")
    try:
        yield "资源使用中"
    finally:
        print("资源清理")

g = resource_manager()
print(next(g))  # 资源初始化 → 资源使用中
g.close()       # 触发 GeneratorExit → 执行 finally → 资源清理

close() 的典型用途是释放生成器持有的外部资源。当生成器被垃圾回收时,Python 会自动调用其 close() 方法,因此通常不需要手动调用——但在需要立即释放资源时,显式调用更可靠。

def file_reader(path):
    f = open(path, "r")
    try:
        for line in f:
            yield line.strip()
    finally:
        f.close()
        print("文件已关闭")

# 只读取前两行就终止
g = file_reader("data.txt")
print(next(g))
print(next(g))
del g  # 垃圾回收时会自动调用 close()

生成器的状态生命周期

生成器对象有三种状态:

  1. GEN_CREATED:已创建,尚未启动。此时只能调用 next() 或 send(None)。
  2. GEN_SUSPENDED:已启动,停在某个 yield 处。可以调用 next()、send()、throw()、close()。
  3. GEN_CLOSED:已关闭(正常结束、抛出未捕获异常、或 close() 被调用)。此时任何操作都会触发 StopIteration 或 RuntimeError。
import inspect

def demo():
    yield 1
    yield 2

g = demo()
print(inspect.getgeneratorstate(g))  # GEN_CREATED
next(g)
print(inspect.getgeneratorstate(g))  # GEN_SUSPENDED
next(g)
print(inspect.getgeneratorstate(g))  # GEN_SUSPENDED(停在第二个 yield)
try:
    next(g)
except StopIteration:
    pass
print(inspect.getgeneratorstate(g))  # GEN_CLOSED

生成器替代类迭代器

任何能用生成器完成的功能,同样可以用基于类的迭代器完成。但生成器的写法更紧凑,因为它自动创建 __iter__() 和 __next__(),自动保存局部变量状态,自动引发 StopIteration。

# 基于类的迭代器(繁琐)
class RangeIterator:
    def __init__(self, start, stop):
        self.current = start
        self.stop = stop
    def __iter__(self):
        return self
    def __next__(self):
        if self.current >= self.stop:
            raise StopIteration
        val = self.current
        self.current += 1
        return val

# 生成器(简洁)
def range_gen(start, stop):
    while start < stop:
        yield start
        start += 1

# 两者行为完全一致
print(list(RangeIterator(0, 3)))  # [0, 1, 2]
print(list(range_gen(0, 3)))      # [0, 1, 2]
上一页
迭代器协议
下一页
生成器表达式