Python的程序结构[6] -> 迭代器/Iterator -> 迭代器浅析
迭代器 / Iteratior
目录
1 可迭代对象与迭代器协议
对于迭代器首先需要了解两个定义,迭代器协议 (Iterator Protocol) 与可迭代对象 (Iterable) ,
迭代器协议 Iterator Protocol:
迭代器协议是指对象能够提供 next() 方法 (__next__()) ,返回迭代中的下一项,或者引起一个 StopIteration 异常,以终止迭代。
可迭代对象 Iterable:
可迭代对象则是指,实现了迭代器协议的对象,例如 list、tuple、dict 等,这些都属于可迭代对象 (Iterable),但是却不是迭代器对象 (Iterator)。但可以使用内建函数 iter(),利用可迭代对象生成一个迭代器对象。
2 迭代器
对于迭代器来说,需要的是一个 __next__() 特殊函数,也就是迭代器与可迭代对象的一个重要差别。通过示例可以看到,可迭代对象是不具有 __next__() 方法的,而迭代器则有。
lis = [1, 2]
print(hasattr(lis, '__iter__')) # True
print(hasattr(lis, '__next__')) # False
lix = iter(lis)
print(hasattr(lix, '__iter__')) # True
print(hasattr(lix, '__next__')) # True
Note:
1. 内置函数 iter() 会调用对象的 __iter__() 方法,因此,可迭代对象具有 __iter__() 方法;
2. 内置函数 next() 会调用对象的 __next__() 方法,因此迭代器则需要具有 __next__() 方法;
3. 当 for 循环处理可迭代对象时,其本质是先调用了可迭代对象的 __iter__() 方法,使其变成迭代器后,再进行 next() 循环迭代。
利用 help 函数分别查看两个对象,
from collections import Iterator, Iterable
help(Iterator)
help(Iterable)
通过对迭代器的查看结果可以发现,Iterator 是以 Iterable 作为基类的,且多了一个 __next__() 方法。
class Iterable(builtins.object)
| Methods defined here:
|
| __iter__(self)
|
| ----------------------------------------------------------------------
| Class methods defined here:
|
| __subclasshook__(C) from abc.ABCMeta
| Abstract classes can override this to customize issubclass().
|
| This is invoked early on by abc.ABCMeta.__subclasscheck__().
| It should return True, False or NotImplemented. If it returns
| NotImplemented, the normal algorithm is used. Otherwise, it
| overrides the normal algorithm (and the outcome is cached).
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| __abstractmethods__ = frozenset({'__iter__'}) Help on class Iterator in module collections.abc: class Iterator(Iterable)
| Method resolution order:
| Iterator
| Iterable
| builtins.object
|
| Methods defined here:
|
| __iter__(self)
|
| __next__(self)
| Return the next item from the iterator. When exhausted, raise StopIteration
|
| ----------------------------------------------------------------------
| Class methods defined here:
|
| __subclasshook__(C) from abc.ABCMeta
| Abstract classes can override this to customize issubclass().
|
| This is invoked early on by abc.ABCMeta.__subclasscheck__().
| It should return True, False or NotImplemented. If it returns
| NotImplemented, the normal algorithm is used. Otherwise, it
| overrides the normal algorithm (and the outcome is cached).
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| __abstractmethods__ = frozenset({'__next__'})
3 迭代器(模拟)的建立
对于一个迭代器的建立,主要是利用 iter() 函数调用可迭代对象内部的 __iter__() 函数返回一个迭代器对象。而此处将建立一个自己的类,来模拟迭代器的一些行为特征。建立的方式可分为两种,一种是直接建立 Iterator,另一种是继承 Iterable。
直接建立 Iterator
直接建立一个类 MyIterator,并完成迭代器必须的特殊方法 __next__ 的定义,同时加入了对 __iter__ 函数的定义,以便在for循环的时候返回实例本身(已具备 __next__ 方法因此只需返回实例即可,后面会介绍模拟可迭代对象的 for 循环迭代器生成)。定义的 __next__ 方法模拟了 range() 的行为。
class MyIterator():
def __init__(self, imin, imax):
self.count = imin - 1
self.limit = imax def __iter__(self):
return self def __next__(self):
self.count += 1
if self.count >= self.limit:
raise StopIteration
return self.count it = MyIterator(0, 7)
for i in range(7):
print(next(it))
# Output: 0 1 2 3 4 5 6 for i in MyIterator(0, 7):
print(i)
# Output: 0 1 2 3 4 5 6
利用 next() 和 for 循环两种方式遍历迭代器,可以看到输出正常。
继承 Iterable
第二种方式需要建立一个自己的可迭代对象,并模拟可迭代对象的行为。定义一个可迭代对象类 MyIterable,对可迭代对象不定义其 __next__ 方法,只定义 __iter__ 方法供 iter() 函数调用,在 __iter__ 方法中,将会利用一个 MyIterable 的子类 geneIterator (模拟 Iterator 基于 Iterable )来生成可迭代对象的子类迭代器。
class MyIterable():
def __init__(self, imin, imax):
self.imin = imin
self.imax = imax
self.count = imin - 1
self.limit = imax #def __iter__(self):
# return self def __iter__(self):
return GeneIterator(self)
这里定义了一个 MyIterable 的子类,GeneIterator 继承自 MyIterable,初始化时接收一个 Iterable 类实例作为参数,并且重载了一个 __next__() 函数用于实现迭代器的特性。
class GeneIterator(MyIterable):
def __init__(self, iterable):
# This __init__ function pass two value to the instance of geneIterator
MyIterable.__init__(self, iterable.imin, iterable.imax) def __next__(self):
self.count += 1
if self.count >= self.limit:
raise StopIteration
return self.count
Note:
此处最值得注意的是,GeneIterator(self) 中的 self 是 MyIterable 的实例,作为初始化时传入参数iterable而存在,而 MyIterable.__init__(self, iterable.imin, iterable.imax) 中的 self 则是 GeneIterator 的实例,此处传入父类的初始化函数中的目的在于,让 self 通过 MyIterable 的初始化获得(继承) count 和 limit 参数。
最后验证迭代器
for i in MyIterable(0, 7):
print(i)
# Output: 0 1 2 3 4 5 6
通过上面两个类的继承关系,此处的 for 循环会先调用 MyIterable 的 __iter__ 方法,获得一个具有 __next__ 方法的 GeneIterator 实例,最终使用 next() 方法进行迭代。
Python的程序结构[6] -> 迭代器/Iterator -> 迭代器浅析的更多相关文章
- Python的程序结构[7] -> 生成器/Generator -> 生成器浅析
生成器 / Generator 目录 关于生成器 生成器与迭代器 生成器的建立 通过迭代生成器获取值 生成器的 close 方法 生成器的 send 方法 生成器的 throw 方法 空生成器的检测方 ...
- Python基本程序结构
条件判断: 计算机之所以能做很多自动化的任务,因为它可以自己做条件判断.比如,输入用户年龄,根据年龄打印不同的内容,在Python程序中,用if语句实现:
- Python的程序结构[5] -> 模块/Module[0] -> 内建模块 builtins
builtins 内建模块 / builtins Module 在Python的模块中,有一种特殊模块,无需导入便可以使用,其中包含了许多内建函数与类. builtins 模块内容 / builtin ...
- Python的程序结构[0] -> 属性/Property[0] -> 类属性、实例属性和私有属性
类属性.实例属性和私有属性 Python中类的属性主要包括类属性,实例属性和私有属性,下面是对三种属性的简单介绍 类属性 / Class Property 类属性在__init__()之外初始化,在外 ...
- Python的程序结构[1] -> 方法/Method[0] -> 类实例方法、私有方法和抽象方法
类实例方法.私有方法和抽象方法 Python中最常用的就是类实例方法,类似于属性中的类实例属性,同时,也存在与私有属性类似方法,即私有方法,下面介绍这两种常见的方法,以及一种特殊意义的类实例方法 -- ...
- Python的程序结构[1] -> 方法/Method[1] -> 静态方法、类方法和属性方法
静态方法.类方法和属性方法 在 Python 中有三种常用的方法装饰器,可以使普通的类实例方法变成带有特殊功能的方法,分别是静态方法.类方法和属性方法. 静态方法 / Static Method 在 ...
- Python的程序结构[1] -> 方法/Method[2] -> 魔术方法 __init__ / __del__ / __new__
魔术方法 / Magic Method 魔法方法就是可以给你的类增加魔力的特殊方法(实质应称为特殊方法,魔术方法在JavaScript中有所体现,对象具有不透明特性,而且无法在自定义对象中模拟这些行为 ...
- Python的程序结构[2] -> 类/Class[0] -> 类的特殊属性
类的特殊属性 / Special Property of Class Python 中通过 class 进行类的定义,类可以实例化成实例并利用实例对方法进行调用. 类中还包含的一些共有的特殊属性. 特 ...
- Python的程序结构[2] -> 类/Class[1] -> 基类与继承
基类与继承 / Base Class and Inheritance Class 面向对象的特性使得 Python 中不可避免地需要使用到类和类的继承,类的继承可以使得代码很好的被重用.下面以一些代码 ...
随机推荐
- 《Cracking the Coding Interview》——第8章:面向对象设计——题目4
2014-04-23 18:17 题目:设计一个停车位的类. 解法:停车位,就要有停车.取车的功能了.另外我还加了一个工作线程用于计费,每秒给那些有车的车位加1块钱费用. 代码: // 8.4 Des ...
- css 之 border-radius属性
css中给盒子设置圆角可以通过 border-radius 属性来实现(具体原理就不深入探讨了); 在开发过程中都会遇到浏览器兼容问题,这问题其实也不难解决,无非就是加上私有前缀,在这里先忽略掉. ...
- [译]15-spring 自动装配
前面的章节我们已经学习了如何使用bean元素在xml配置文件中声明一个bean.也学习了如何使用bean的子元素contructor-arg 和property进行bean的依赖项的注入. 之前bea ...
- PHP vscode+XDebug 远程断点调试服务器上的代码
对于简单的项目或仅仅想知道某一位置的某个变量是什么值,直接使用var_dump配置exit来打印和中断就可以了,方便又快捷, 而对于大型项目的调试,或想了解某个系统的整个运行过程,xdebug可能会是 ...
- MapReduce架构
主从结构 主节点:JobTracker(一个) 从节点:TaskTrackers(多个) JobTracker: 接收客户提交的计算任务 把计算任务分配给TaskTrackers执行 监控TaskTr ...
- 【bzoj1706】[usaco2007 Nov]relays 奶牛接力跑 离散化+倍增Floyd
题目描述 FJ的N(2 <= N <= 1,000,000)头奶牛选择了接力跑作为她们的日常锻炼项目.至于进行接力跑的地点 自然是在牧场中现有的T(2 <= T <= 100) ...
- vue实现多个元素或多个组件之间动画效果
多个元素的过渡 <style> .v-enter,.v-leave-to{ opacity: 0; } .v-enter-acitve,.v-leave-active{ opacity: ...
- [poj] 3690 Constellations || 矩阵hash
原题 在大矩阵里找有几个小矩阵出现过,多组数据 将t个矩阵hash值放入multiset,再把大矩阵中每个hash值从multiset里扔出去,这样最后剩在multiset里的值就是没有找到的小矩阵, ...
- POJ 1204 Word Puzzles | AC 自动鸡
题目: 给一个字母矩阵和几个模式串,矩阵中的字符串可以有8个方向 输出每个模式串开头在矩阵中出现的坐标和这个串的方向 题解: 我们可以把模式串搞成AC自动机,然后枚举矩阵最外围一层的每个字母,向八个方 ...
- 熊猫(i)
题目描述 熊猫喜欢吃数,熊猫对与每个数都有他独特的评价.具体来说,熊猫对数 xx 的评价是个四元组 (a, b, c, d)(a,b,c,d),计算方式如下: 首先将 xx 写成二进制形式(不含前导零 ...