Python案例怎么实现迭代器模式?

wen python案例 77

Python案例:如何优雅实现迭代器模式?——从零到精通的设计模式实战

目录导读

  1. 迭代器模式核心概念:为什么需要它?
  2. Python内置迭代器与可迭代对象速览
  3. 手写迭代器模式:经典案例(遍历自定义树结构)
  4. 进阶优化:生成器与__iter__/__next__的取舍
  5. 常见陷阱与问答(Q&A)
  6. 何时该用迭代器模式?

迭代器模式核心概念:为什么需要它?

迭代器模式(Iterator Pattern)是一种行为型设计模式,它允许顺序访问集合对象的元素,而不暴露其底层表示,在Python中,我们几乎每天都在无意识地使用它——for item in listfor line in file等等,但如果你需要遍历一个复杂的数据结构(如二叉树、分级菜单、虚拟数据流),手动实现迭代器就变得至关重要。

Python案例怎么实现迭代器模式?

核心角色

  • 迭代器(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中,生成器函数恰好是实现迭代器最简洁的方式。


何时该用迭代器模式?

如果你遇到以下情况,可以动手实现自定义迭代器:

  1. 遍历复杂结构 – 树、图、迷宫、神经网络层。
  2. 延迟加载大数据 – 从数据库或文件逐条读取,而非一次性加载到内存。
  3. 实现多种遍历策略 – 同一个容器支持前序、后序、层序遍历(通过不同的迭代器类)。
  4. 封装迭代逻辑 – 隐藏内部数据结构,只暴露统一的for接口。

最后一句:迭代器模式让Python的for循环变得万能——你只需让对象可迭代,剩下的交给语言机制。


本文由AI生成,但已综合多篇技术文章进行去重与优化,符合SEO最佳实践。

抱歉,评论功能暂时关闭!