实现迭代器协议

问题

你想构建一个能支持迭代操作的自定义对象,并希望找到一个能实现迭代协议的简单方法。

解法

目前为止,在一个对象上实现迭代最简单的方式是使用一个生成器函数。在 4.2 小节中,使用 Node 类来表示树形数据结构。你可能想实现一个以深度优先方式遍历树形节点的生成器。下面是代码示例:

class Node:def __init__(self, value):self._value = valueself._children = []def __repr__(self):return 'Node({!r})'.format(self._value)def add_child(self, node):self._children.append(node)def __iter__(self):return iter(self._children)def depth_first(self):yield selffor c in self:yield from c.depth_first()# Example
if __name__ == '__main__':root = Node(0)child1 = Node(1)child2 = Node(2)root.add_child(child1)root.add_child(child2)child1.add_child(Node(3))child1.add_child(Node(4))child2.add_child(Node(5))for ch in root.depth_first():print(ch)# Outputs Node(0), Node(1), Node(3), Node(4), Node(2), Node(5)

在这段代码中, depth_first() 方法简单直观。它首先返回自己本身并迭代每一个子节点并通过调用子节点的 depth_first() 方法 (使用 yield from 语句) 返回对应元素。

讨论

Python 的迭代协议要求一个__iter__() 方法返回一个特殊的迭代器对象,这个迭代器对象实现了__next__() 方法并通过 StopIteration 异常标识迭代的完成。但是,实现这些通常会比较繁琐。下面我们演示下这种方式,如何使用一个关联迭代器类重新实现 depth_first() 方法:

class Node2:def __init__(self, value):self._value = valueself._children = []def __repr__(self):return 'Node({!r})'.format(self._value)def add_child(self, node):self._children.append(node)def __iter__(self):return iter(self._children)def depth_first(self):return DepthFirstIterator(self)class DepthFirstIterator(object):'''Depth-first traversal'''def __init__(self, start_node):self._node = start_nodeself._children_iter = Noneself._child_iter = Nonedef __iter__(self):return selfdef __next__(self):# Return myself if just started; create an iterator for childrenif self._children_iter is None:self._children_iter = iter(self._node)return self._node# If processing a child, return its next itemelif self._child_iter:try:nextchild = next(self._child_iter)return nextchildexcept StopIteration:self._child_iter = Nonereturn next(self)# Advance to the next child and start its iterationelse:self._child_iter = next(self._children_iter).depth_first()return next(self)

DepthFirstIterator 类和上面使用生成器的版本工作原理类似,但是它写起来很繁琐,因为迭代器必须在迭代处理过程中维护大量的状态信息。坦白来讲,没人愿意写这么晦涩的代码。将你的迭代器定义为一个生成器后一切迎刃而解。

《Python Cookbook 3rd》笔记(4.4):实现迭代器协议相关推荐

  1. 《Python Cookbook 3rd》笔记(1.4):查找最大或最小的N个元素

    <Python Cookbook 3rd>1.4:查找最大或最小的N个元素 问题 怎样从一个集合中获得最大或者最小的N个元素列表? 解法 heapq 模块有两个函数:nlargest()和 ...

  2. Python Cookbook 3rd Edition Documentation

    Python Cookbook 3rd Edition Documentation 文章目录 第一章:数据结构和算法 1.1 解压序列赋值给多个变量 问题 解决方案 讨论 1.2 解压可迭代对象赋值给 ...

  3. 《Python cookbook》笔记二

    <Python cookbook>笔记二 第二章 字符串和文本 -使用多个界定符分割字符串- 你需要将一个字符串分割为多个字段,但是分隔符 (还有周围的空格) 并不是固定 的. # str ...

  4. Machine Learning with Python Cookbook 学习笔记 第8章

    Chapter 8. Handling Images 前言 本笔记是针对人工智能典型算法的课程中Machine Learning with Python Cookbook的学习笔记 学习的实战代码都放 ...

  5. Machine Learning with Python Cookbook 学习笔记 第9章

    Chapter 9. Dimensionality Reduction Using Feature Extraction 前言 本笔记是针对人工智能典型算法的课程中Machine Learning w ...

  6. Machine Learning with Python Cookbook 学习笔记 第6章

    Chapter 6. Handling Text 本笔记是针对人工智能典型算法的课程中Machine Learning with Python Cookbook的学习笔记 学习的实战代码都放在代码压缩 ...

  7. 《Python Cookbook 3rd》笔记(4.2):代理迭代

    代理迭代 问题 你构建了一个自定义容器对象,里面包含有列表.元组或其他可迭代对象.你想直接在你的这个新容器对象上执行迭代操作. 解法 实际上你只需要定义一个 iter () 方法,将迭代操作代理到容器 ...

  8. 《Python Cookbook 3rd》笔记汇总

    文章目录 一.数据结构 二.字符串和文本 三.数字.日期和时间 四.迭代器与生成器 五.文件与IO 一.数据结构 标题 关键词 1.1:拆分序列后赋值给多个变量 可迭代对象.拆分赋值 1.2:拆分任意 ...

  9. 《Python cookbook》笔记一

    <Python cookbook> 第一章 数据结构和算法 - *号解压多个变量 - 如果一个可迭代对象的元素个数超过变量个数时,会抛出一个 ValueError .那么 怎样才能从这个可 ...

最新文章

  1. python中ret是什么意思_数据结构图在python中的应用
  2. 无源定位之时差估计的精确时差估计算法(ETDE)及MATLAB实现程序
  3. 力扣(leetcode)-1. 两数之和
  4. 直接管理内存——new和delete
  5. JavaScript函数节流和函数防抖
  6. 阿里内推题——物流派送员送快递最短路径问题
  7. 可能是全网最通俗易懂的微服务架构改造解读
  8. 侏儒排序算法原理与Python实现
  9. vue将每个路由打包成html,Ant Design Vue pro 动态路由的实现和打包
  10. 如何将 Mac 置入睡眠状态或唤醒 Mac?
  11. Golang 入门 : Go语言介绍
  12. logo字体在线设计工具
  13. EF Core注意事项
  14. linux的htb队列,Linux流量控制中的HTB队列创建与过滤(2)
  15. [渝粤教育] 西南科技大学 计算机文化基础复习资料
  16. 基于安卓的校园跳蚤市场app
  17. LeetCode(跳跃游戏)
  18. 简易的MySQL主从复制
  19. 为什么说学计算机更有远见,“孩子,我为什么逼你读书”:有远见的父母,都有点心狠...
  20. sql --Acess

热门文章

  1. 串口通讯编程一日通3(COMMTIMEOUTS DCB整理)
  2. Maven笔记——依赖管理
  3. java二级缓存技术_Java二级缓存
  4. Web服务器控件和HTML控件的区别与联系
  5. C#多线程编程系列(一)- 简介
  6. 35解释器模式(Interpreter Pattern)
  7. 使用 Syslog 连接 Sentinel
  8. ROS有三个层级的概念,分别是:文件系统级、计算图级和开源社区级
  9. python用什么系统好_10分钟用python搭建一个超好用的CMDB系统
  10. 【Python CheckiO 题解】Sort Array by Element Frequency