Python中生成器和迭代器的区别详解


Posted in Python onFebruary 10, 2018

Python中生成器和迭代器的区别(代码在Python3.5下测试):

Num01?>迭代器

定义:

对于list、string、tuple、dict等这些容器对象,使用for循环遍历是很方便的。在后台for语句对容器对象调用iter()函数。iter()是python内置函数。

iter()函数会返回一个定义了next()方法的迭代器对象,它在容器中逐个访问容器内的元素。next()也是python内置函数。在没有后续元素时,next()会抛出一个StopIteration异常,通知for语句循环结束。

迭代器是用来帮助我们记录每次迭代访问到的位置,当我们对迭代器使用next()函数的时候,迭代器会向我们返回它所记录位置的下一个位置的数据。实际上,在使用next()函数的时候,调用的就是迭代器对象的_next_方法(Python3中是对象的_next_方法,Python2中是对象的next()方法)。所以,我们要想构造一个迭代器,就要实现它的_next_方法。但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现_iter_方法,而_iter_方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的_iter_方法返回自身self即可。

一些术语的解释:

1,迭代器协议:对象需要提供next()方法,它要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代。
2,可迭代对象:实现了迭代器协议对象。list、tuple、dict都是Iterable(可迭代对象),但不是Iterator(迭代器对象)。但可以使用内建函数iter() ,把这些都变成Iterable(可迭代器对象)。
3,for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束

Python自带容器对象案例:

# 随便定义一个list
listArray=[1,2,3]
# 使用iter()函数
iterName=iter(listArray)
print(iterName)
# 结果如下:是一个列表list的迭代器
# <list_iterator object at 0x0000017B0D984278>

print(next(iterName))
print(next(iterName))
print(next(iterName))
print(next(iterName))#没有迭代到下一个元素,直接抛出异常
# 1
# 2
# 3
# Traceback (most recent call last):
# File "Test07.py", line 32, in <module>
# StopIteration

Python中一个实现了_iter_方法和_next_方法的类对象,就是迭代器,如下案例是计算菲波那切数列的案例

class Fib(object):
 def __init__(self, max):
  super(Fib, self).__init__()
  self.max = max

 def __iter__(self):
  self.a = 0
  self.b = 1
  return self

 def __next__(self):
  fib = self.a
  if fib > self.max:
   raise StopIteration
  self.a, self.b = self.b, self.a + self.b
  return fib

# 定义一个main函数,循环遍历每一个菲波那切数
def main():
 # 20以内的数
 fib = Fib(20)
 for i in fib:
  print(i)

# 测试
if __name__ == '__main__':
 main()

解释说明:

在本类的实现中,定义了一个_iter_(self)方法,这个方法是在for循环遍历时被iter()调用,返回一个迭代器。因为在遍历的时候,是直接调用的python内置函数iter() ,由iter()通过调用_iter_(self)获得对象的迭代器。有了迭代器,就可以逐个遍历元素了。而逐个遍历的时候,也是使用内置的next()函数通过调用对象的_next_(self)方法对迭代器对象进行遍历。所以要实现_iter_(self)_next_(self)这两个方法。

而且因为实现了_next_(self)方法,所以在实现_iter_(self)的时候,直接返回self就可以。

总结一句话就是:

在循环遍历自定义容器对象时,会使用python内置函数iter()调用遍历对象的_iter_(self)获得一个迭代器,之后再循环对这个迭代器使用next()调用迭代器对象的_next_(self)

注意点: _iter_(self)只会被调用一次,而_next_(self)会被调用 n 次,直到出现StopIteration异常。

Num02?>生成器

作用:

>延迟操作。也就是在需要的时候才产生结果,不是立即产生结果。

注意事项:

>生成器是只能遍历一次的。
>生成器是一类特殊的迭代器。

分类:

第一类:生成器函数:还是使用 def 定义函数,但是,使用yield而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。

如下案例加以说明:

# 菲波那切数列
def Fib(max):
 n, a, b = 0, 0, 1
 while n < max:
  yield b
  a, b = b, a + b
  n = n + 1
 return '亲!没有数据了...'
# 调用方法,生成出10个数来
f=Fib(10)
# 使用一个循环捕获最后return 返回的值,保存在异常StopIteration的value中
while True:
 try:
  x=next(f)
  print("f:",x)
 except StopIteration as e:
  print("生成器最后的返回值是:",e.value)
  break

第二类:生成器表达式:类似于列表推导,只不过是把一对大括号[]变换为一对小括号()。但是,生成器表达式是按需产生一个生成器结果对象,要想拿到每一个元素,就需要循环遍历。

如下案例加以说明:

# 一个列表
xiaoke=[2,3,4,5]
# 生成器generator,类似于list,但是是把[]改为()
gen=(a for a in xiaoke)
for i in gen:
 print(i)
#结果是:
2
3
4
5

# 为什么要使用生成器?因为效率。
# 使用生成器表达式取代列表推导式可以同时节省 cpu 和 内存(RAM)。
# 如果你构造一个列表(list)的目的仅仅是传递给别的函数,
# 比如 传递给tuple()或者set(), 那就用生成器表达式替代吧!

# 本案例是直接把列表转化为元组
kk=tuple(a for a in xiaoke)
print(kk)
#结果是:
(2, 3, 4, 5)

# python内置的一些函数,可以识别这是生成器表达式,外面有一对小括号,就是生成器
result1=sum(a for a in range(3))
print(result1)
# 列表推导式
result2=sum([a for a in range(3)])
print(result2)

总结

以上就是本文关于Python中生成器和迭代器的区别详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

Python 相关文章推荐
python缩进区别分析
Feb 15 Python
Python实现抓取页面上链接的简单爬虫分享
Jan 21 Python
Python实现对excel文件列表值进行统计的方法
Jul 25 Python
Python使用Matplotlib实现雨点图动画效果的方法
Dec 23 Python
Python实现对文件进行单词划分并去重排序操作示例
Jul 10 Python
Python模块/包/库安装的六种方法及区别
Feb 24 Python
python通过对字典的排序,对json字段进行排序的实例
Feb 27 Python
Python数据结构dict常用操作代码实例
Mar 12 Python
属性与 @property 方法让你的python更高效
Sep 21 Python
快速解决pymongo操作mongodb的时区问题
Dec 05 Python
python中numpy.empty()函数实例讲解
Feb 05 Python
python lambda的使用详解
Feb 26 Python
详解python中的线程
Feb 10 #Python
Odoo中如何生成唯一不重复的序列号详解
Feb 10 #Python
python TCP Socket的粘包和分包的处理详解
Feb 09 #Python
python实现Adapter模式实例代码
Feb 09 #Python
python实现Decorator模式实例代码
Feb 09 #Python
Python多线程扫描端口代码示例
Feb 09 #Python
Python编程实现从字典中提取子集的方法分析
Feb 09 #Python
You might like
PHP 选项及相关信息函数库
2006/12/04 PHP
简单说说PHP优化那些事(经验分享)
2014/11/27 PHP
Zend Framework框架之Zend_Mail实现发送Email邮件验证功能及解决标题乱码的方法
2016/03/21 PHP
jQuery操作Select的Option上下移动及移除添加等等
2013/11/18 Javascript
选择复选框按钮置灰否则按钮可用
2014/05/22 Javascript
自己动手手写jQuery插件总结
2015/01/20 Javascript
js实现带关闭按钮始终显示在网页最底部工具条的方法
2015/03/02 Javascript
jquery对象和DOM对象的任意相互转换
2016/02/21 Javascript
JavaScript实现99乘法表及隔行变色实例代码
2016/02/24 Javascript
JS获取当前脚本文件的绝对路径
2016/03/02 Javascript
关于angularJs清除浏览器缓存的方法
2017/11/28 Javascript
深入浅析Vue中的Prop
2018/06/10 Javascript
微信小程序收藏功能的实现代码
2018/06/12 Javascript
详解vue 2.6 中 slot 的新用法
2019/07/09 Javascript
vue远程加载sfc组件思路详解
2019/12/25 Javascript
[01:04:48]VGJ.S vs TNC Supermajor 败者组 BO3 第一场 6.6
2018/06/07 DOTA
Python中join函数简单代码示例
2018/01/09 Python
利用Python批量提取Win10锁屏壁纸实战教程
2018/03/27 Python
pandas 使用均值填充缺失值列的小技巧分享
2019/07/04 Python
python实现KNN分类算法
2019/10/16 Python
解决Python命令行下退格,删除,方向键乱码(亲测有效)
2020/01/16 Python
python生成并处理uuid的实现方式
2020/03/03 Python
Python爬虫之爬取淘女郎照片示例详解
2020/07/28 Python
Python logging日志库空间不足问题解决
2020/09/14 Python
管理科学大学生求职信
2013/11/13 职场文书
新店开张活动方案
2014/08/24 职场文书
党性观念心得体会
2014/09/03 职场文书
运动会稿件100字
2014/09/24 职场文书
综治维稳工作汇报
2014/10/27 职场文书
房屋授权无偿使用证明
2014/11/29 职场文书
2015纪念九一八事变84周年演讲稿
2015/03/19 职场文书
毕业生爱心捐书倡议书
2015/04/27 职场文书
2016五一手机促销广告语
2016/01/28 职场文书
行政后勤人员工作计划应该怎么写?
2019/08/16 职场文书
八年级作文之感恩
2019/11/22 职场文书
Python机器学习应用之工业蒸汽数据分析篇详解
2022/01/18 Python