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中的列表推导浅析
Apr 26 Python
python利用正则表达式搜索单词示例代码
Sep 24 Python
使用python中的in ,not in来检查元素是不是在列表中的方法
Jul 06 Python
Python3获取拉勾网招聘信息的方法实例
Apr 03 Python
基于Python实现大文件分割和命名脚本过程解析
Sep 29 Python
Python操作多维数组输出和矩阵运算示例
Nov 28 Python
python wav模块获取采样率 采样点声道量化位数(实例代码)
Jan 22 Python
如何使用PyCharm将代码上传到GitHub上(图文详解)
Apr 27 Python
在keras里面实现计算f1-score的代码
Jun 15 Python
paramiko使用tail实时获取服务器的日志输出详解
Dec 06 Python
Python实现简单的猜单词
Jun 15 Python
Python装饰器的练习题
Nov 23 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数组去重的函数代码
2013/02/03 PHP
PHP遍历数组的三种方法及效率对比分析
2015/02/12 PHP
PHP中PDO的事务处理分析
2016/04/07 PHP
Mootools 图片展示插件(lightbox,ImageMenu)收集集合
2010/05/21 Javascript
简单实用的js调试logger组件实现代码
2010/11/20 Javascript
自定义一个jquery插件[鼠标悬浮时候 出现说明label]
2011/06/27 Javascript
读jQuery之十四 (触发事件核心方法)
2011/08/23 Javascript
JS获取iframe中longdesc属性的方法
2015/04/01 Javascript
jQuery控制网页打印指定区域的方法
2015/04/07 Javascript
逐一介绍Jquery data()、Jquery stop()、jquery delay()函数(详)
2015/11/04 Javascript
jQuery动画效果图片轮播特效
2016/01/12 Javascript
javascript创建含数字字母的随机字符串方法总结
2016/08/01 Javascript
jQuery实现的多张图无缝滚动效果【测试可用】
2016/09/12 Javascript
Node.js dgram模块实现UDP通信示例代码
2017/09/26 Javascript
css和js实现弹出登录居中界面完整代码
2017/11/26 Javascript
快速解决vue-cli不能初始化webpack模板的问题
2018/03/20 Javascript
简单了解Vue computed属性及watch区别
2020/07/10 Javascript
vue-video-player实现实时视频播放方式(监控设备-rtmp流)
2020/08/10 Javascript
JavaScript字符串转数字的简单实现方法
2020/11/27 Javascript
[00:34]DOTA2上海特级锦标赛 VG战队宣传片
2016/03/04 DOTA
python创建只读属性对象的方法(ReadOnlyObject)
2013/02/10 Python
Python入门篇之字典
2014/10/17 Python
Python网络爬虫实例讲解
2016/04/28 Python
启动targetcli时遇到错误解决办法
2017/10/26 Python
python 3.6 tkinter+urllib+json实现火车车次信息查询功能
2017/12/20 Python
pycharm中导入模块错误时提示Try to run this command from the system terminal
2020/03/26 Python
Python如何操作office实现自动化及win32com.client的运用
2020/04/01 Python
python装饰器三种装饰模式的简单分析
2020/09/04 Python
python实现登录与注册系统
2020/11/30 Python
浅析移动设备HTML5页面布局
2015/12/01 HTML / CSS
国外最大的眼镜网站:Coastal
2017/08/09 全球购物
荷兰在线体育用品商店:Avantisport.nl
2018/07/04 全球购物
2014领导班子四风剖析对照检查材料思想汇报
2014/09/20 职场文书
保卫工作个人总结
2015/03/03 职场文书
mysql查询的控制语句图文详解
2021/04/11 MySQL
pytorch MSELoss计算平均的实现方法
2021/05/12 Python