⚡ 19. 迭代器与生成器

本章概述

学习 Python 的迭代器和生成器,高效处理序列数据。 预计学习时间:50 分钟


19.1 什么是迭代

可以用 for 循环遍历的就是可迭代对象。

可迭代对象 Iterable

可以被迭代的对象,有 __iter__() 方法。

常见的可迭代对象:

  • 列表、元组、字符串、字典、集合
  • range 对象
  • 文件对象
  • 生成器
# 这些都是可迭代对象
for i in [1, 2, 3]:       # 列表
    pass
 
for c in "hello":         # 字符串
    pass
 
for k in {"a": 1}:        # 字典
    pass
 
for i in range(5):        # range
    pass

判断是否可迭代

from collections.abc import Iterable
 
print(isinstance([1, 2, 3], Iterable))  # True
print(isinstance(123, Iterable))        # False

19.2 迭代器 Iterator

迭代器是有 __next__() 方法的对象,一次返回一个值。

iter() 和 next()

lst = [1, 2, 3]
 
# iter() 获取迭代器
it = iter(lst)
 
# next() 获取下一个值
print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
print(next(it))  # StopIteration(没有更多元素了)

for 循环的本质

for 循环的本质就是先获取迭代器,然后不断调用 next(),直到遇到 StopIteration。

# for 循环
for item in [1, 2, 3]:
    print(item)
 
# 等价于
it = iter([1, 2, 3])
while True:
    try:
        item = next(it)
        print(item)
    except StopIteration:
        break

可迭代对象 vs 迭代器

类型特点示例
可迭代对象__iter__(),可以被 for 循环列表、字符串、字典
迭代器__next__(),可以调用 next()iter(列表)、生成器

关系

  • 迭代器一定是可迭代对象
  • 可迭代对象不一定是迭代器
  • iter() 可以把可迭代对象变成迭代器

19.3 自定义迭代器

自己写一个类,实现 __iter__()__next__() 方法。

示例:斐波那契数列迭代器

class Fibonacci:
    def __init__(self, max_count):
        self.max_count = max_count
        self.count = 0
        self.a = 0
        self.b = 1
 
    def __iter__(self):
        return self  # 返回迭代器本身
 
    def __next__(self):
        if self.count >= self.max_count:
            raise StopIteration  # 停止迭代
 
        result = self.a
        self.a, self.b = self.b, self.a + self.b
        self.count += 1
        return result
 
# 使用
fib = Fibonacci(10)
for num in fib:
    print(num)

19.4 生成器 Generator

生成器是一种特殊的迭代器,用 yield 关键字创建,更简洁。

生成器函数

def count_down(n):
    while n > 0:
        yield n  # 暂停,返回值
        n -= 1
 
# 调用生成器函数,返回生成器对象
gen = count_down(5)
print(gen)  # <generator object count_down at ...>
 
# 可以用 for 循环遍历
for i in gen:
    print(i)

yield 的特点

yield vs return

  • return:函数结束,返回值
  • yield:函数暂停,返回值,下次 next() 从暂停处继续
def demo():
    print("开始")
    yield 1
    print("暂停后继续")
    yield 2
    print("再暂停后继续")
    yield 3
    print("结束")
 
gen = demo()
 
print(next(gen))  # 开始 \n 1
print(next(gen))  # 暂停后继续 \n 2
print(next(gen))  # 再暂停后继续 \n 3
print(next(gen))  # 结束 \n StopIteration

19.5 生成器表达式

类似列表推导式,但用小括号,返回生成器。

基本用法

# 列表推导式(立即生成所有元素,占内存)
lst = [x**2 for x in range(10)]
print(lst)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
 
# 生成器表达式(惰性计算,省内存)
gen = (x**2 for x in range(10))
print(gen)  # <generator object <genexpr> at ...>
 
# 遍历生成器
for num in gen:
    print(num)

生成器的优势

  • 省内存:一次只生成一个值,不用把所有数据都放内存里
  • 惰性计算:用到的时候才计算
  • 处理大数据时特别有用

带条件的生成器表达式

# 只生成偶数的平方
gen = (x**2 for x in range(10) if x % 2 == 0)

19.6 生成器的方法

send() 发送数据

def echo():
    while True:
        msg = yield  # 接收发送的值
        print(f"收到:{msg}")
 
gen = echo()
next(gen)  # 启动生成器,停在yield处
 
gen.send("你好")  # 收到:你好
gen.send("世界")  # 收到:世界

throw() 抛出异常

def demo():
    try:
        yield 1
        yield 2
        yield 3
    except ValueError:
        print("捕获到ValueError")
 
gen = demo()
next(gen)  # 1
gen.throw(ValueError)  # 捕获到ValueError

close() 关闭生成器

def demo():
    try:
        yield 1
        yield 2
    finally:
        print("生成器关闭了")
 
gen = demo()
next(gen)  # 1
gen.close()  # 生成器关闭了

19.7 yield from

从另一个生成器中 yield 所有值。

基本用法

def inner():
    yield 1
    yield 2
    yield 3
 
def outer():
    # 方式1:手动循环
    # for x in inner():
    #     yield x
 
    # 方式2:用 yield from
    yield from inner()
 
for num in outer():
    print(num)

应用场景

  • 生成器嵌套
  • 协程(高级话题)

19.8 生成器的应用场景

1. 处理大数据

# 读取大文件,逐行处理,不占内存
def read_large_file(file_path):
    with open(file_path, "r", encoding="utf-8") as f:
        for line in f:
            yield line.strip()
 
for line in read_large_file("big_file.txt"):
    # 处理每一行
    pass

2. 无限序列

# 无限的斐波那契数列
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b
 
fib = fibonacci()
for i in range(10):
    print(next(fib))

3. 管道(流水线)

def numbers():
    for i in range(10):
        yield i
 
def square(nums):
    for n in nums:
        yield n ** 2
 
def even(nums):
    for n in nums:
        if n % 2 == 0:
            yield n
 
# 流水线:生成数字 → 平方 → 过滤偶数
result = even(square(numbers()))
for num in result:
    print(num)

19.9 迭代工具 itertools

Python 标准库提供了很多迭代工具。

常用函数

import itertools
 
# count:无限计数
for i in itertools.count(10, 2):  # 从10开始,步长2
    if i > 20:
        break
    print(i)
 
# cycle:无限循环
for i, c in enumerate(itertools.cycle("ABC")):
    if i >= 6:
        break
    print(c)
 
# repeat:重复
for i in itertools.repeat("hello", 3):
    print(i)
 
# chain:连接多个可迭代对象
for i in itertools.chain([1, 2], [3, 4], [5, 6]):
    print(i)
 
# product:笛卡尔积
for a, b in itertools.product("AB", [1, 2]):
    print(a, b)
 
# permutations:排列
for p in itertools.permutations([1, 2, 3], 2):
    print(p)
 
# combinations:组合
for c in itertools.combinations([1, 2, 3], 2):
    print(c)

itertools 很强大

处理迭代相关的问题时,先看看 itertools 有没有现成的。


🔗 相关章节


📝 我的笔记

在这里记录你的理解、疑问和练习代码

# 你的练习代码
 

✅ 本章检查清单

  • 理解可迭代对象和迭代器的概念
  • 会使用 iter() 和 next()
  • 会自定义迭代器
  • 掌握生成器函数和 yield
  • 会使用生成器表达式
  • 了解生成器的 send/throw/close 方法
  • 了解 yield from
  • 知道生成器的应用场景
  • 了解 itertools 模块