python设计模式之迭代器与生成器详解(五)
前言
迭代器是设计模式中的一种行为模式,它提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。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表示的不是元组而是生成器
总结
可迭代对象的定义时是对象定义了__iter__方法,迭代器的定义是对象实现了__iter__和__next__魔法方法;
迭代遍历停止的标志是抛出StopIteration异常,for循环会自动捕捉这个异常停止迭代;
参考
- 作者:天宇之游
- 出处:http://www.cnblogs.com/cwp-bg/
- 本文版权归作者和博客园共有,欢迎转载、交流,但未经作者同意必须保留此段声明,且在文章明显位置给出原文链接。
python设计模式之迭代器与生成器详解(五)的更多相关文章
- python迭代器与生成器详解
迭代器与生成器 迭代器(iterator)与生成器(generator)是 Python 中比较常用又很容易混淆的两个概念,今天就把它们梳理一遍,并举一些常用的例子. for 语句与可迭代对象(ite ...
- python编程系列---可迭代对象,迭代器和生成器详解
一.三者在代码上的特征 1.有__iter__方法的对象就是可迭代类(对象) 2.有__iter__方法,__next()方法的对象就是迭代器3.生成器 == 函数+yield 生成器属于迭代器, 迭 ...
- python 迭代器和生成器详解
一.迭代器 说迭代器之前有两个相关的名词需要介绍:可迭代对象:只要定义了__iter__()方法,我们就说该对象是可迭代对象,并且可迭代对象能提供迭代器.迭代器:实现了__next__()或者next ...
- [js高手之路] es6系列教程 - 迭代器与生成器详解
什么是迭代器? 迭代器是一种特殊对象,这种对象具有以下特点: 1,所有对象都有一个next方法 2,每次调用next方法,都会返回一个对象,该对象包含两个属性,一个是value, 表示下一个将要返回的 ...
- Python学习一:序列基础详解
作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7858473.html 邮箱:moyi@moyib ...
- Python学习二:词典基础详解
作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7862377.html 邮箱:moyi@moyib ...
- python 3.x 爬虫基础---Urllib详解
python 3.x 爬虫基础 python 3.x 爬虫基础---http headers详解 python 3.x 爬虫基础---Urllib详解 前言 爬虫也了解了一段时间了希望在半个月的时间内 ...
- python中argparse模块用法实例详解
python中argparse模块用法实例详解 这篇文章主要介绍了python中argparse模块用法,以实例形式较为详细的分析了argparse模块解析命令行参数的使用技巧,需要的朋友可以参考下 ...
- python selenium 三种等待方式详解[转]
python selenium 三种等待方式详解 引言: 当你觉得你的定位没有问题,但是却直接报了元素不可见,那你就可以考虑是不是因为程序运行太快或者页面加载太慢造成了元素不可见,那就必须要加等待 ...
随机推荐
- ios 中不new Date 的格式 不支持年月日 以‘-’ 分割的格式
new Date("2018-1-5") 在 ios 中显示 invalid date - 换做 / 则可以顺利显示 new Date("2018/1/5")
- android面试(5)---SQL数据库
SQL基础: 1.如何查询table1从20到30条记录: select * from table1 limit 19,11 2.替换id=1,name =deman的记录? replace into ...
- Contest 6
A:容易发现这要求所有子集中元素的最高位1的位置相同,并且满足这个条件也是一定合法的.统计一下即可. #include<iostream> #include<cstdio> # ...
- mysql主从复制 master和slave配置的参数大全
master所有参数1 log-bin=mysql-bin 1.控制master的是否开启binlog记录功能: 2.二进制文件最好放在单独的目录下,这不但方便优化.更方便维护. 3.重新命名二进制日 ...
- 洛谷 P3802 小魔女帕琪 解题报告
P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...
- 【bzoj4002】有意义的字符串
Portal --> bzoj4002 Solution 虽然说这题有点强行但是感觉还是挺妙的,给你通项让你反推数列的这种==有点毒 补档时间 首先有一个东西叫做特征方程,我们可以 ...
- Yii2 数据库基本操作
//1.简单查询 $admin=Admin::model()->findAll($condition,$params); $admin=Admin::model()->findAll( ...
- C++时间
C++时间 头文件 chrono, 命名空间 std. 现在时间 std::chrono::system_clock::now() 返回系统时钟的当前时间 时钟 std::chrono::system ...
- php 三元运算符简洁用法
<?php header('Content-type:text;charset=utf8'); $a = 'aaaa'; $b = $a ?:'; $c = $a ? $a : '; //这个和 ...
- 二型错误和功效(Type II Errors and Test Power)
sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&am ...