首页 / Python3 入门教程 / 迭代器与生成器

Python3 入门教程

迭代器与生成器

本教程共 70 篇 · 第 26 篇 · 更新于 2026-07-22 · 约 3 分钟阅读

PythonPython3 入门教程迭代器生成器yieldyield from

26. 迭代器与生成器

本节目标:理解迭代器协议,掌握 yield 的用法,能用生成器处理大数据流。

迭代器是什么

迭代器是「能记住遍历位置」的对象。它有两个核心方法:

  • __iter__():返回迭代器自身
  • __next__():返回下一个元素,没有时抛出 StopIteration
>>> nums = [1, 2, 3]
>>> it = iter(nums)      # 获取迭代器
>>> next(it)
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
StopIteration
Note

迭代器只能往前,不能后退,也不能重复遍历。想再来一次,得重新 iter()

for 循环的本质

for 循环底层就是迭代器:

for x in iterable:
    print(x)

# 等价于
it = iter(iterable)
while True:
    try:
        x = next(it)
        print(x)
    except StopIteration:
        break

自定义迭代器

实现 __iter____next__ 方法:

class CountDown:
    def __init__(self, start):
        self.start = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.start <= 0:
            raise StopIteration
        self.start -= 1
        return self.start + 1

for n in CountDown(5):
    print(n)
# 5 4 3 2 1

生成器函数

yield 关键字,可以更简单地把函数变成生成器:

def countdown(n):
    while n > 0:
        yield n
        n -= 1

for x in countdown(5):
    print(x)
# 5 4 3 2 1
Tip

yield 会暂停函数执行并返回一个值,下次从暂停处继续。这比普通函数「一口气算完所有结果再返回」省内存得多。

生成器函数返回的是生成器对象:

>>> gen = countdown(3)
>>> gen
<generator object countdown at 0x...>
>>> next(gen)
3
>>> next(gen)
2

生成器表达式

前面推导式章节提过,圆括号包起来就是生成器表达式:

>>> gen = (x ** 2 for x in range(10))
>>> gen
<generator object <genexpr> at 0x...>
>>> sum(gen)
285

用生成器处理大文件

读取大文件时,不用一次性加载到内存:

def read_lines(filename):
    with open(filename, 'r', encoding='utf-8') as f:
        for line in f:
            yield line.strip()

for line in read_lines('big_file.txt'):
    process(line)   # 逐行处理,内存只存一行
Tip

文件对象本身就是迭代器,for line in f 已经是一行一行读了。但把逻辑封装成生成器函数,能让代码更清晰、更可复用。

生成器的数据传递

yield 不仅可以返回值,还能接收值:

def echo():
    while True:
        received = yield
        print(f"收到: {received}")

e = echo()
next(e)       # 启动生成器(或 e.send(None))
e.send("hello")
e.send("world")
# 收到: hello
# 收到: world
Warning

生成器启动前必须先 next()send(None),让执行流到第一个 yield 处。不然直接 send 会报错。

yield from

Python 3.3+ 的 yield from 可以把另一个生成器的值委托出来:

def sub_generator():
    yield 1
    yield 2

def main_generator():
    yield 'a'
    yield from sub_generator()
    yield 'b'

print(list(main_generator()))
# ['a', 1, 2, 'b']

这在写协程、递归生成器时很方便。

什么时候用生成器

场景推荐
数据量巨大,内存吃紧生成器
需要惰性计算、按需取值生成器
需要随机访问、多次遍历列表
数据量小,操作简单列表
Note

生成器是惰性求值的,只能遍历一次。如果需要多次遍历或随机访问,转成列表:list(generator)。但要确保数据量不会撑爆内存。


来源:参考了 runoob「Python3 迭代器与生成器」、liaoxuefeng「函数式编程」等,改写后所得。