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》——第12章:测试——题目3
2014-04-24 23:28 题目:玩象棋游戏,你要设计一个bool型的方法来检测一个棋子能否移动到指定位置. 解法:不同的棋子有不同的移动规则,那么应该采取棋子基类实现接口,各个棋子子类来实现的 ...
- springboot示例参考网站
https://blog.csdn.net/u013248535/article/details/55100979/
- 孤荷凌寒自学python第十八天python变量的作用范围
孤荷凌寒自学python第十八天python函数的形参与变量的范围 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.在python的函数中各种不同的形式参数在定义的先后顺序上有规定: 必须 ...
- Day4 自定义控件/ListView/RecyclerView
创建自定义控件 引入布局 在新增的title.xml中创建一个自定义的标题栏: <LinearLayout xmlns:android="http://schemas.android. ...
- Servlet 返回Json数据格式
其实就是把数据库中的数据查询出来拼接成一个Json数据 import dao.UserDao; import endy.User; import javax.servlet.ServletExcept ...
- Android React Native组件的生命周期及回调函数
熟悉android的童鞋应该都清楚,android是有生命周期的,其很多组件也是有生命周期.今天小编和大家分享的React Native组件的生命周期,还不了解的童鞋,赶紧来围观吧 在android开 ...
- 【CF Edu 28 C. Four Segments】
time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...
- 机器学习-- Logistic回归 Logistic Regression
转载自:http://blog.csdn.net/linuxcumt/article/details/8572746 1.假设随Tumor Size变化,预测病人的肿瘤是恶性(malignant)还是 ...
- 为什么说for循环设置循环变量的那部分是一个父作用域?
最近在看阮一峰老师的<ES6> 看到let时,发现一处for循环很神奇的地方. 书中的原话是:“另外,for循环还有一个特别之处,就是设置变量的那部分是一个父作用域,而循环体内部是一个单独 ...
- yum 和 apt-get
yum 和apt-get 一般来说著名的linux系统基本上分两大类: 1.RedHat系列:Redhat.Centos.Fedora等 2.Debian系列:Debian.Ubuntu等 RedHa ...