前言

迭代器是设计模式中的一种行为模式,它提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。python提倡使用生成器,生成器也是迭代器的一种。

系列文章

python可迭代对象和迭代器

要点

  • 迭代即遍历,那么可迭代对象顾名思义就是可以遍历的数据类型或结构,表现在python中就是支持for循环遍历的对象。

  • python中有Iterable类代表可迭代对象,所有的可迭代对象都属于这个类;Iterator类表示迭代器,所有的迭代器对象都属于这个类;

  • 可迭代对象为什么可迭代?因为可迭代对象的内部实现了迭代器这种行为模式,其在python中的表现就是__iter__魔法方法。也就是说所有python内建的数据结构如str、list等预先已在定义结构时使用__iter__方法实现了迭代器.

可迭代对象和迭代器的原理

根据上面的要点我们自定义可迭代对象:

from collections import Iterable

class MyIterable(object):

    def __iter__(self):
pass my_iter = MyIteradle() print(isinstance(my_iter,Iterable)) # 结果:
True

说明python解释器是通过判断一个对象是否有__iter__魔法方法来确定是否是可迭代对象。现在我们尝试用for...in...遍历一下我们定义的可迭代对象:

my_iter = MyIter()
for i in my_iter:
print(i) 结果:
TypeError: iter() returned non-iterator of type 'NoneType'

报错了,为什么?我们需要知道for...in...干了什么事:

python解释器遇到for...in关键字时,第一步找到in后面的my_iter对象,寻找内部的__iter__魔法方法,如果有就执行这个方法,该方法会生成一个迭代器;

第二步从迭代器中取出一个值,并将这个值赋值给i.

那么清楚了,上述我们虽然有了__iter__魔法方法,但是它并不会返回一个迭代器,从迭代器中取值这个动作也没有。那么我们需要实现一个迭代器。

为了便于理解,我们把可迭代对象想象成一个容器,里面存放了我们的数据;迭代器想象成以可迭代对象为原型,在上面加装了一种方法可以顺序访问一个可迭代对象中各个元素,for循环干的事就是获取这个迭代器并从迭代器中取数据。

记住:可迭代对象和它的迭代器是两个不同的对象。

如此我们可知,既然迭代器的原型是可迭代对象,那么自然也要有__iter__魔法方法了,可是这个方法要求返回一个迭代器,那么不无限循环了吗?我们可以让其返回它自己就可以了。另外要加一个方法实现从迭代器中取数据啊,python解释器规定这个方法为_next_.

from collections import Iterable, Iterator
class MyIterator(object): def __iter__(self):
return self def __next__(self):
return 0
my_iterator = MyIterator()
print(isinstance(my_iterator, Iterator))
for i in my_iterator:
print(i) # 结果:
True

没有报错,由此我们可知在python中实现了__iter__和__next__方法的对象就是迭代器。

完成了吗?并没有,看迭代器定义:提供一种方法顺序访问一个聚合对象中各个元素;顺序访问,由此有:

class MyIterator(object):

    def __init__(self, mylist):
self.mylist = mylist
# current用来记录当前访问到的位置
self.current = 0 def __next__(self):
if self.current < len(self.mylist):
item = self.mylist[self.current]
self.current += 1
return item
else:
raise StopIteration def __iter__(self):
return self

显性获取和使用迭代器

使用for...in...关键字,python解释器把获取迭代器和从迭代器中取值的过程全部自动完成了,如果我想手动一步步实现这个过程怎么办呢?python提供了显性的方法iter()和next().

# 两种方法可以获取一个对象的迭代器
l = [0,1,2]
print(l.__iter__())
print(iter(l)) # 结果:
<list_iterator object at 0x000002567EA5C518>
<list_iterator object at 0x000002567EA5C518>
  • 手动遍历
# 使用next方法取值
l = [0,1,2]
ter = iter(l)
print(ter)
while True:
try:
print(next(ter))
except StopIteration:
break

生成器

生成器是一类特殊的迭代器,什么意思?假如我们想自定义一个迭代器,那么我们需要手动实现__iter__和__next__方法,这显然太过麻烦,于是python为我们提供了一个简单快速的方法。

def my_iterator(mylist):
current = 0
while current < len(mylist):
res = mylist[current]
current += 1
yield res
return '遍历完成' l = [0,1,2,3]
F = my_iterator(l)
for i in F:
print(i)

可以看到,我们把__next__方法中的逻辑抽出来,使用yield返回一个结果,这种简便的结构就是生成器了,本质上是一种快速获得迭代器的方法。

此时my_iterator的return值通过for循环是获取不到的,而是需要StopIteration捕捉。

l = [0,1,2,3]
F = my_iterator(l)
while True:
try:
next(F)
except StopIteration as e:
print("生成器返回值:%s"%e.value)
break

此时的next()函数可以唤醒生成器,另外我们可以使用send()方法来唤醒生成器,同时传递一个值到生成器中。

def my_iterator(mylist):
current = 0
while current < len(mylist):
res = mylist[current]
current += 1
i = yield res
print(i)
return '遍历完成' l = [0,1,2,3]
F = my_iterator(l)
while True:
try:
f.send('aaaa')
except StopIteration as e:
print("生成器返回值:%s"%e.value)
break

生成器生成式

在逻辑足够简单的时候,一个更快捷的创建生成器的方法:

f = (i for i in range(10)) # 此时f表示的不是元组而是生成器

总结

  1. 可迭代对象的定义时是对象定义了__iter__方法,迭代器的定义是对象实现了__iter__和__next__魔法方法;

  2. 迭代遍历停止的标志是抛出StopIteration异常,for循环会自动捕捉这个异常停止迭代;

参考

  • 作者:天宇之游
  • 出处:http://www.cnblogs.com/cwp-bg/
  • 本文版权归作者和博客园共有,欢迎转载、交流,但未经作者同意必须保留此段声明,且在文章明显位置给出原文链接。

python设计模式之迭代器与生成器详解(五)的更多相关文章

  1. python迭代器与生成器详解

    迭代器与生成器 迭代器(iterator)与生成器(generator)是 Python 中比较常用又很容易混淆的两个概念,今天就把它们梳理一遍,并举一些常用的例子. for 语句与可迭代对象(ite ...

  2. python编程系列---可迭代对象,迭代器和生成器详解

    一.三者在代码上的特征 1.有__iter__方法的对象就是可迭代类(对象) 2.有__iter__方法,__next()方法的对象就是迭代器3.生成器 == 函数+yield 生成器属于迭代器, 迭 ...

  3. python 迭代器和生成器详解

    一.迭代器 说迭代器之前有两个相关的名词需要介绍:可迭代对象:只要定义了__iter__()方法,我们就说该对象是可迭代对象,并且可迭代对象能提供迭代器.迭代器:实现了__next__()或者next ...

  4. [js高手之路] es6系列教程 - 迭代器与生成器详解

    什么是迭代器? 迭代器是一种特殊对象,这种对象具有以下特点: 1,所有对象都有一个next方法 2,每次调用next方法,都会返回一个对象,该对象包含两个属性,一个是value, 表示下一个将要返回的 ...

  5. Python学习一:序列基础详解

    作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7858473.html 邮箱:moyi@moyib ...

  6. Python学习二:词典基础详解

    作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7862377.html 邮箱:moyi@moyib ...

  7. python 3.x 爬虫基础---Urllib详解

    python 3.x 爬虫基础 python 3.x 爬虫基础---http headers详解 python 3.x 爬虫基础---Urllib详解 前言 爬虫也了解了一段时间了希望在半个月的时间内 ...

  8. python中argparse模块用法实例详解

    python中argparse模块用法实例详解 这篇文章主要介绍了python中argparse模块用法,以实例形式较为详细的分析了argparse模块解析命令行参数的使用技巧,需要的朋友可以参考下 ...

  9. python selenium 三种等待方式详解[转]

    python selenium 三种等待方式详解   引言: 当你觉得你的定位没有问题,但是却直接报了元素不可见,那你就可以考虑是不是因为程序运行太快或者页面加载太慢造成了元素不可见,那就必须要加等待 ...

随机推荐

  1. Apache Hadoop YARN – ResourceManager--转载

    原文地址:http://zh.hortonworks.com/blog/apache-hadoop-yarn-resourcemanager/ ResourceManager (RM) is the ...

  2. 【bzoj5174】[Jsoi2013]哈利波特与死亡圣器 二分+树形dp

    题目描述 给你一棵以1为根的有根树,初始除了1号点为黑色外其余点均为白色.Bob初始在1号点.每次Alice将其中至多k个点染黑,然后Bob移动到任意一个相邻节点,重复这个过程.求最小的k,使得无论B ...

  3. BZOJ4881 线段游戏(二分图+树状数组/动态规划+线段树)

    相当于将线段划分成两个集合使集合内线段不相交,并且可以发现线段相交等价于逆序对.也即要将原序列划分成两个单增序列.由dilworth定理,如果存在长度>=3的单减子序列,无解,可以先判掉. 这个 ...

  4. 【SPOJ】QTREE6(Link-Cut-Tree)

    [SPOJ]QTREE6(Link-Cut-Tree) 题面 Vjudge 题解 很神奇的一道题目 我们发现点有黑白两种,又是动态加边/删边 不难想到\(LCT\) 最爆力的做法,显然是每次修改单点颜 ...

  5. 洛谷 U14472 数据结构【比赛】 【差分数组 + 前缀和】

    题目描述 蒟蒻Edt把这个问题交给了你 ---- 一个精通数据结构的大犇,由于是第一题,这个题没那么难.. edt 现在对于题目进行了如下的简化: 最开始的数组每个元素都是0 给出nnn,optopt ...

  6. 框架----Django框架知识点整理

    一.cbv cbv(class-base-view) 基于类的视图 fbv(func-base-view) 基于函数的视图 a.基本演示 urlpatterns = [ url(r'^login.ht ...

  7. Spring Swagger URL传参问题(转)

    代码例子: @ApiOperation(value="获取用户详细信息", notes="根据url的id来获取用户详细信息") @ApiImplicitPar ...

  8. 【计算机视觉】SIFT中LoG和DoG比较

    <SIFT原理与源码分析>系列文章索引:http://www.cnblogs.com/tianyalu/p/5467813.html 在实际计算时,三种方法计算的金字塔组数noctaves ...

  9. bzoj2962 序列操作

    2962: 序列操作 Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 1145  Solved: 378[Submit][Status][Discuss ...

  10. Codeforces 894.D Ralph And His Tour in Binary Country

    D. Ralph And His Tour in Binary Country time limit per test 2.5 seconds memory limit per test 512 me ...