Python生成器迭代与next()调用行为差异及统一方法问询
Python生成器迭代与next()调用的行为差异解析
生成器函数定义
def f123(): lista = range(2) print("2: before yields") yield [lista, "A: yield"] print("- after yield A") yield [lista, "B: yield"] print("- after yield B") yield [lista, "C: yield"] print("- after yield C")
两种调用方式
示例1(next()手动调用)
print("0: -----") print("1: start") list_gener = f123() example = list() example.append(next(list_gener)) example.append(next(list_gener)) example.append(next(list_gener)) print("3: end") print(example)
示例2(迭代遍历)
print("0: -----") print("1: start") example = [item for item in f123()] print("3: end") print(example)
结果对比
两种方式得到的example内容完全一致:
[ [range(0, 2), 'A: yield'], [range(0, 2), 'B: yield'], [range(0, 2), 'C: yield'] ]
但控制台输出存在差异:
| 示例1输出 | 示例2输出 |
|---|---|
| 0: ----- | 0: ----- |
| 1: start | 1: start |
| 2: before yields | 2: before yields |
| - after yield A | - after yield A |
| - after yield B | - after yield B |
| 3: end | - after yield C |
| 3: end |
疑问解答
为什么迭代遍历会打印“- after yield C”?
生成器的迭代逻辑是:迭代器(比如列表推导式)遍历生成器时,会持续调用next()直到捕获到StopIteration异常才停止。
示例1中仅调用3次next(),刚好获取3个yield的返回值,此时生成器函数执行到第三个yield之后的print("- after yield C")之前就暂停——没有第四次next()调用触发后续代码执行。
示例2的列表推导式会完成完整迭代:获取第三个yield的值后,还会再调用一次next(),此时生成器函数会执行完第三个yield之后的print("- after yield C"),随后因无更多yield语句抛出StopIteration异常,迭代器捕获异常后停止遍历,这就是示例2会打印该内容的原因。
如何让示例1的行为与示例2一致?
只需要在示例1中,获取3个yield值后主动触发生成器执行剩余代码,有两种方式:
方式1:手动调用一次next()并捕获异常
print("0: -----") print("1: start") list_gener = f123() example = list() example.append(next(list_gener)) example.append(next(list_gener)) example.append(next(list_gener)) # 调用next()触发剩余代码执行,捕获终止异常 try: next(list_gener) except StopIteration: pass print("3: end") print(example)
方式2:用for循环完成完整迭代
print("0: -----") print("1: start") list_gener = f123() example = [] for item in list_gener: example.append(item) print("3: end") print(example)
修改后示例1的输出会和示例2完全一致。
内容的提问来源于stack exchange,提问作者José Victor
相关产品推荐
相关产品推荐

