Python迭代器与生成器:优雅的惰性计算艺术

一、迭代器协议:__iter__和__next__的魔法

迭代器的本质

Python中的迭代器不是存储所有元素的容器,而是惰性计算的协议实现。核心在于两个方法:

  • __iter__():返回迭代器自身
  • __next__():返回下一个元素,耗尽时抛出StopIteration
python 复制代码
class CountDown:
    """自定义迭代器:倒计时"""
    def __init__(self, start):
        self.current = start
    
    def __iter__(self):
        return self  # 迭代器必须返回自身
    
    def __next__(self):
        if self.current <= 0:
            raise StopIteration
        num = self.current
        self.current -= 1
        return num

# 使用
for num in CountDown(5):
    print(num)  # 输出: 5 4 3 2 1

迭代器的优势

  • 内存高效:不一次性加载所有数据
  • 无限序列:可以表示无限长的序列
  • 通用接口 :统一的for循环处理方式

二、生成器:yield的暂停与恢复魔法

生成器函数

生成器是创建迭代器的语法糖 ,使用yield暂停函数执行并返回值:

python 复制代码
def fibonacci_generator(limit):
    """生成斐波那契数列"""
    a, b = 0, 1
    count = 0
    while count < limit:
        yield a  # 暂停执行,返回a
        a, b = b, a + b
        count += 1

# 生成器对象
fib_gen = fibonacci_generator(10)
print(next(fib_gen))  # 0
print(next(fib_gen))  # 1
print(list(fib_gen))  # [1, 2, 3, 5, 8, 13, 21, 34]

生成器表达式

更简洁的生成器创建方式:

python 复制代码
# 传统列表推导(立即计算)
squares_list = [x**2 for x in range(1000000)]  # 占用大量内存

# 生成器表达式(惰性计算)
squares_gen = (x**2 for x in range(1000000))  # 几乎不占内存
print(next(squares_gen))  # 0
print(next(squares_gen))  # 1

三、yield from:生成器的委派机制

简化嵌套生成器

python 复制代码
def chain_generators(*iterables):
    """连接多个可迭代对象"""
    for iterable in iterables:
        yield from iterable  # 委派给子生成器

# 等效于:
# for item in iterable:
#     yield item

result = list(chain_generators([1, 2], 'ab', (True, False)))
# [1, 2, 'a', 'b', True, False]

四、生成器的高级用法

1. 协程:双向通信

python 复制代码
def coroutine_generator():
    """接收外部数据的生成器"""
    total = 0
    while True:
        value = yield total  # 暂停并接收发送的值
        if value is None:
            break
        total += value

coro = coroutine_generator()
next(coro)  # 启动生成器(预激)
print(coro.send(10))  # 10
print(coro.send(20))  # 30
coro.close()  # 关闭生成器

2. 上下文管理

python 复制代码
from contextlib import contextmanager

@contextmanager
def managed_resource():
    """生成器实现的上下文管理器"""
    print("获取资源")
    resource = "资源对象"
    try:
        yield resource
    finally:
        print("释放资源")

with managed_resource() as r:
    print(f"使用 {r}")

五、性能对比:迭代器 vs 列表

python 复制代码
import time
import sys

def test_memory_usage():
    """内存使用对比"""
    # 列表:一次性加载所有数据
    list_data = [i for i in range(1000000)]
    print(f"列表内存: {sys.getsizeof(list_data):,} bytes")
    
    # 生成器:惰性计算
    gen_data = (i for i in range(1000000))
    print(f"生成器内存: {sys.getsizeof(gen_data):,} bytes")

def test_performance():
    """性能对比"""
    n = 10_000_000
    
    # 列表推导
    start = time.time()
    _ = [x**2 for x in range(n)]
    list_time = time.time() - start
    
    # 生成器表达式
    start = time.time()
    _ = (x**2 for x in range(n))
    gen_time = time.time() - start
    
    print(f"列表推导: {list_time:.3f}s")
    print(f"生成器表达式: {gen_time:.3f}s")

test_memory_usage()
test_performance()

六、实用模式与陷阱

1. 生成器的一次性使用

python 复制代码
gen = (x for x in range(3))
print(list(gen))  # [0, 1, 2]
print(list(gen))  # [] !已耗尽

2. itertools模块的迭代器工具

python 复制代码
from itertools import islice, count, cycle

# 无限序列的切片
first_10 = list(islice(count(10), 5))  # [10, 11, 12, 13, 14]

# 循环迭代器
cycler = cycle('ABC')
print([next(cycler) for _ in range(6)])  # ['A', 'B', 'C', 'A', 'B', 'C']

3. 自定义可迭代对象

python 复制代码
class BatchProcessor:
    """分批处理大数据集"""
    def __init__(self, data, batch_size):
        self.data = data
        self.batch_size = batch_size
    
    def __iter__(self):
        """返回生成器迭代器"""
        for i in range(0, len(self.data), self.batch_size):
            yield self.data[i:i + self.batch_size]

data = list(range(100))
batcher = BatchProcessor(data, 10)
for batch in batcher:
    process(batch)  # 每次处理10个元素

总结

迭代器和生成器是Python惰性计算哲学的体现,它们通过:

  1. 按需计算节省内存
  2. 统一的迭代协议简化API设计
  3. 生成器协程实现复杂控制流
  4. 优雅的语法让代码更清晰
相关推荐
威哥爱编程17 分钟前
Python 智能体开发实战 05:一问教材内容它就编?先把答案从你自己的资料里检索出来
python·agent
java_prinln22 分钟前
RAG 面试题介绍
python·agent
威哥爱编程25 分钟前
Python 智能体开发实战 06:一个函数里塞了八百行?用状态机把批改流程拆成能回退的步骤
python·agent
Patrick在香港1 小时前
一个斜杠,把毫秒变成十几秒
android·数据库·python·性能优化·正则表达式·回溯·redos
2601_967980111 小时前
Python 初学者必备的常用内置函数
python·编程语言·内置函数·初学者·常用函数
OnlineProxy1 小时前
移动应用数据爬取:通过模拟器与流量嗅探对 API 进行逆向工程
爬虫·python·httpx
染指11102 小时前
162.Agent-LangGraph-检查点的作用
人工智能·python·langchain·agents
我命由我123452 小时前
访客系统形式(有用户概念、无用户概念)
java·开发语言·前端·javascript·python·产品运营·产品经理
xixingzhe22 小时前
图表中同比与环比的区别:看趋势还是看变化?
开发语言·python
forest_093 小时前
当 AI 搜索开始「自我进化」,谁来进化它的核实?——「已核实」结论复核器:3 条结论挖出 2 个洞(附可运行代码)
人工智能·python·机器学习·prompt·agi