Python3 迭代器与生成器(建议收藏)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在 Python3 开发中,迭代器与生成器是处理序列化数据的核心工具。它们如同程序中的“数据流水线”,既能高效管理内存资源,又能灵活控制数据流的生成逻辑。无论是遍历列表、处理无限序列,还是优化内存密集型任务,掌握这两个概念都将显著提升代码的性能与可读性。本文将从基础概念出发,结合生动的比喻和代码示例,帮助读者逐步理解迭代器与生成器的实现原理及应用场景。


一、迭代器(Iterator):数据流的“导航仪”

1.1 什么是可迭代对象?

在 Python 中,任何可以被遍历的对象(如列表、元组、字符串)都称为可迭代对象(Iterable)。它们内部实现了 __iter__() 方法,该方法会返回一个迭代器。例如:

numbers = [1, 2, 3]  
iterator = iter(numbers)  # 调用 __iter__() 方法,获取迭代器对象  
print(next(iterator))     # 输出 1  

这里,iter() 函数将列表 numbers 转换为迭代器,next() 函数则逐个取出元素。

1.2 迭代器协议:双方法规则

迭代器必须实现两个核心方法:

  • __iter__(): 返回迭代器对象本身(通常返回 self)。
  • __next__(): 返回序列中的下一个元素,若无元素则抛出 StopIteration 异常。

比喻
想象一个图书馆的目录索引,__iter__() 是打开目录的动作,而 __next__() 是逐页翻阅书名的过程。目录一旦被打开,就能按顺序访问所有书籍,直到最后一页结束。

1.3 手动实现迭代器

通过自定义类,我们可以创建一个简单的迭代器:

class CounterIterator:  
    def __init__(self, stop):  
        self.current = 0  
        self.stop = stop  

    def __iter__(self):  
        return self  

    def __next__(self):  
        if self.current < self.stop:  
            value = self.current  
            self.current += 1  
            return value  
        else:  
            raise StopIteration  

counter = CounterIterator(3)  
for num in counter:  
    print(num)  # 输出 0, 1, 2  

此例中,CounterIterator 类实现了迭代器协议,可生成从 0stop-1 的整数序列。


二、生成器(Generator):代码的“智能流水线”

2.1 生成器函数:用 yield 简化迭代逻辑

生成器是一种特殊的迭代器,其核心是 yield 关键字。与 return 不同,yield 可以暂停函数执行并返回值,待下次调用时继续执行。例如:

def simple_generator():  
    yield 1  
    yield 2  
    yield 3  

gen = simple_generator()  
print(next(gen))  # 输出 1  
print(next(gen))  # 输出 2  

每次调用 next(gen) 会恢复函数执行,直到遇到下一个 yield 或函数结束。

2.2 生成器表达式:简洁的数据流构建

生成器表达式类似于列表推导式,但用圆括号包裹,返回生成器对象:

even_numbers = (x for x in range(10) if x % 2 == 0)  
for num in even_numbers:  
    print(num)  # 输出 0, 2, 4, 6, 8  

与列表推导式相比,生成器表达式按需生成元素,节省内存。

2.3 惰性求值:生成器的性能优势

生成器通过惰性求值(Lazy Evaluation),仅在需要时计算下一个值。例如,生成斐波那契数列时:

def fibonacci(n):  
    a, b = 0, 1  
    for _ in range(n):  
        yield a  
        a, b = b, a + b  

fib = fibonacci(5)  
print(list(fib))  # 输出 [0, 1, 1, 2, 3]  

若用列表存储所有斐波那契数,当 n 极大时(如 1000000),内存消耗将显著增加,而生成器能逐个生成并释放临时变量。


三、迭代器与生成器的对比

特性迭代器生成器
实现方式需定义 __iter__()__next__()通过 yield 关键字简化实现
内存占用需预先存储所有数据按需生成,内存友好
复杂度手动管理状态变量状态自动保存,代码更简洁
适用场景自定义复杂迭代逻辑需要惰性求值或处理无限序列时

比喻
迭代器如同传统生产线——需要提前规划所有步骤;而生成器则像智能流水线,根据需求动态调整生产节奏,无需囤积半成品。


四、实战案例:用生成器优化内存密集型任务

4.1 处理大文件的逐行读取

假设需要读取一个 1GB 的日志文件,逐行统计关键词出现次数。使用生成器可避免一次性加载整个文件:

def read_large_file(file_path):  
    with open(file_path, 'r') as file:  
        for line in file:  
            yield line.strip()  

log_lines = read_large_file('large_log.txt')  
for line in log_lines:  
    # 执行分析逻辑  
    pass  

此方法仅在循环时逐行读取文件,内存占用接近 O(1)

4.2 生成无限序列:自然数流

def infinite_counter():  
    num = 0  
    while True:  
        yield num  
        num += 1  

counter = infinite_counter()  
for _ in range(5):  
    print(next(counter))  # 输出 0, 1, 2, 3, 4  

此生成器可无限生成自然数,适合需要循环计数的场景(如模拟时钟)。


五、进阶技巧:生成器的 send() 与异常处理

5.1 send() 方法:向生成器传递数据

通过 send() 可在生成器内部恢复执行时传入值,常用于协程(Coroutine)设计:

def calculator():  
    while True:  
        expr = (yield)  # 接收外部传入的表达式  
        try:  
            result = eval(expr)  
            yield result  
        except Exception as e:  
            yield str(e)  

calc = calculator()  
next(calc)  # 初始化生成器  
print(calc.send("2 + 3"))  # 输出 5  
print(calc.send("a / 0"))  # 输出 division by zero  

此处 send() 允许外部动态修改生成器的计算逻辑。

5.2 异常处理:优雅终止或重置

在迭代过程中,可通过抛出 StopIteration 或捕获异常来控制流程:

def robust_generator():  
    try:  
        while True:  
            value = yield  
            if value is None:  
                raise ValueError("Invalid input")  
            yield value * 2  
    except GeneratorExit:  
        print("Generator closed gracefully")  

gen = robust_generator()  
next(gen)  # 初始化  
print(gen.send(5))  # 输出 10  
gen.close()         # 触发 GeneratorExit 异常  

结论

迭代器与生成器是 Python3 中处理序列化数据的基石。迭代器通过严格的协议规范,提供了底层的控制能力;而生成器借助 yield 关键字,以更简洁的方式实现了惰性求值和状态管理。两者结合,既能优化内存使用,又能提升代码的可维护性。对于开发者而言,掌握这两个工具,不仅能解决日常开发中的常见问题(如大文件处理、无限序列生成),更能为理解高级编程范式(如协程、异步IO)打下坚实基础。

在实际应用中,建议优先使用生成器表达式或生成器函数来替代手动实现的迭代器,以降低代码复杂度。同时,结合 send() 和异常处理,可以进一步扩展生成器的功能边界,应对更复杂的场景需求。

最新发布