Python案例:如何优雅实现迭代器模式?——从零到精通的设计模式实战
目录导读
- 迭代器模式核心概念:为什么需要它?
- Python内置迭代器与可迭代对象速览
- 手写迭代器模式:经典案例(遍历自定义树结构)
- 进阶优化:生成器与
__iter__/__next__的取舍 - 常见陷阱与问答(Q&A)
- 何时该用迭代器模式?
迭代器模式核心概念:为什么需要它?
迭代器模式(Iterator Pattern)是一种行为型设计模式,它允许顺序访问集合对象的元素,而不暴露其底层表示,在Python中,我们几乎每天都在无意识地使用它——for item in list、for line in file等等,但如果你需要遍历一个复杂的数据结构(如二叉树、分级菜单、虚拟数据流),手动实现迭代器就变得至关重要。

核心角色:
- 迭代器(Iterator):定义
__next__()方法,返回下一个元素,无元素时抛出StopIteration。 - 可迭代对象(Iterable):定义
__iter__()方法,返回一个迭代器实例。
问答1:Python中的
for循环底层是如何工作的?
答:for x in obj首先调用iter(obj),然后反复调用next()直到StopIteration,这解释了为什么所有可迭代对象都能被for消费。
Python内置迭代器与可迭代对象速览
Python已提供了极其丰富的迭代工具:
- 列表、元组、字典、集合、字符串 都是可迭代对象。
range()、open()、zip()、map()返回迭代器。itertools模块 提供无限迭代器(如count)、组合迭代器等。
但内置的迭代器无法满足自定义遍历逻辑,比如你需要后序遍历一个二叉树,或者分页加载数据库查询结果——这时就要自己实现。
手写迭代器模式:经典案例(遍历自定义树结构)
案例描述
实现一个二叉树类,能够按深度优先(前序) 遍历所有节点。
代码实现
class TreeNode:
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
class DepthFirstIterator:
"""前序遍历迭代器:根→左→右"""
def __init__(self, root):
self.stack = [root] # 使用栈辅助遍历
def __iter__(self):
return self
def __next__(self):
if not self.stack:
raise StopIteration
current = self.stack.pop()
# 注意:先压右子节点,再压左子节点,确保左子节点先被处理
if current.right:
self.stack.append(current.right)
if current.left:
self.stack.append(current.left)
return current.value
class BinaryTree:
def __init__(self, root):
self.root = root
def __iter__(self):
return DepthFirstIterator(self.root)
使用示例
# 构建树: 1
# / \
# 2 3
# / \
# 4 5
root = TreeNode(1, TreeNode(2, TreeNode(4), TreeNode(5)), TreeNode(3))
tree = BinaryTree(root)
for val in tree:
print(val, end=' ') # 输出: 1 2 4 5 3
关键点解析
DepthFirstIterator实现了完整的迭代器协议(__iter__返回自身,__next__返回值)。- 使用栈来模拟递归,避免系统递归深度限制。
BinaryTree.__iter__返回一个新迭代器,保证多次遍历相互独立。
问答2:为什么不在
BinaryTree中直接实现__next__,而要多写一个类?
答:因为BinaryTree本身是数据容器,如果同时实现__next__,它就会变成自己的迭代器,导致只能被遍历一次,分开设计符合“职责单一原则”,且支持多次独立遍历。
进阶优化:生成器与__iter__/__next__的取舍
Python生成器(yield)是迭代器模式的语法糖,我们完全可以用生成器改写上面的例子:
class BinaryTree:
def __init__(self, root):
self.root = root
def __iter__(self):
# 使用生成器函数实现前序遍历
def traverse(node):
if node:
yield node.value # 前序:先根
yield from traverse(node.left)
yield from traverse(node.right)
return traverse(self.root) # 返回生成器对象
生成器 vs 手动迭代器: | 对比项 | 手动迭代器 | 生成器 | |--------|-----------|--------| | 代码量 | 较多 | 简洁 | | 灵活性 | 可存储额外状态 | 状态隐含在yield中 | | 性能 | 稍快(无yield开销) | 几乎无差异 | | 适用场景 | 复杂状态管理 | 绝大多数遍历需求 |
建议:优先用生成器,除非你需要暂停/恢复迭代或修改迭代过程中栈的状态。
常见陷阱与问答(Q&A)
Q1:迭代器用完了还能复原吗?
答:不能,迭代器是“一次性”的,如果想要重置,必须重新调用iter()获取新迭代器,或者像我们案例中那样,让容器对象的__iter__每次都返回新迭代器。
Q2:如何实现双向迭代或索引迭代?
答:Python标准库没有直接的双向迭代器接口,但你可以增加一个__reversed__()方法(用于反向迭代),索引迭代则可以通过__getitem__支持,此时iter()会退化为索引调用。
Q3:迭代器模式与“生成器模式”有什么关系?
答:两者没有直接关系,生成器模式(Generator Pattern)是创建型设计模式,用于复杂对象的创建;而迭代器模式是行为型,只是在Python中,生成器函数恰好是实现迭代器最简洁的方式。
何时该用迭代器模式?
如果你遇到以下情况,可以动手实现自定义迭代器:
- 遍历复杂结构 – 树、图、迷宫、神经网络层。
- 延迟加载大数据 – 从数据库或文件逐条读取,而非一次性加载到内存。
- 实现多种遍历策略 – 同一个容器支持前序、后序、层序遍历(通过不同的迭代器类)。
- 封装迭代逻辑 – 隐藏内部数据结构,只暴露统一的
for接口。
最后一句:迭代器模式让Python的for循环变得万能——你只需让对象可迭代,剩下的交给语言机制。
本文由AI生成,但已综合多篇技术文章进行去重与优化,符合SEO最佳实践。