Python生成器与迭代器

前言

首先,来让我们弄清楚可迭代对象

可迭代对象

在python中,可迭代对象并不是指某种具体的数据类型,它是指存储了元素的一个容器对象

也就是说,如果容器里面没有存储数据,那它就不是可迭代对象,并不是所有的容器都是可迭代对象,容器包含但并不仅限于可迭代对象

注意

  • 很多容器都是可迭代对象(容器包含了可迭代对象)
  • 一个可迭代对象是不能独立的进行迭代的,迭代是通过for来完成的,凡是可迭代对象都可以直接使用for循环进行访问

例子

for循环的执行过程

1.使用 __iter__() 返回1个迭代器2.使用 __next__() 获取迭代器中的每一个元素。

代码实现

l = [1,2,3,4]
# for i in l:
#     print(i)
ite =l.__iter__() #接收一下ietr()干了什么print(ite)  #打印,不可超过总的迭代次数,否则会报错print(ite.__next__())    #for循环干第2件事情的时候做的第1步
print(ite.__next__())    #for循环干第2件事情的时候做的第2步
print(ite.__next__())    #for循环干第2件事情的时候做的第3步
print(ite.__next__())    #for循环干第2件事情的时候做的第4步

分析

可以看出来,如果我们去掉哪行打印ite的代码,执行效果就是跟for循环输出列表里面的每一个元素是一样的,for循环里面限定了范围是4次,实际上就执行了1次__iter__()和4次__next__(),也就是说for循环访问迭代对象的本质就是通过这么去实现的。

而且,for循环本质上干的那两件事情,缺一不可,也就是说如果没有__iter__()先返回了迭代器,__next()__也无法获取到元素,恰恰说明了前面说要注意的两点中的第2点:一个可迭代对象是不能独立的进行迭代的。

有两个内置函数跟它们原理是一样的,本质相同,一般要用的话用内置函数要方便一些,起码不用写那么多下划线

内置函数 iter() 的本质是 __inter__() ,也是返回一个迭代器。内置函数 next() 的本质是 __next__(),也是有了迭代器之后获取元素。

生成器

引言

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

在 Python 中,使用了 yield 的函数被称为生成器(generator)。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。调用一个生成器函数,返回的是一个迭代器对象。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>

注:要访问 g 中元素,可使用 next() 方法

这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个

generator:

>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成

generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIterationvalue中:

>>> g = fib(6)
>>> while True:
...     try:
...         x = next(g)
...         print('g:', x)
...     except StopIteration as e:
...         print('Generator return value:', e.value)
...         break
...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done

小结

generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。

要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

请注意区分普通函数和generator函数,普通函数调用直接返回结果:

>>> r = abs(6)
>>> r
6

generator函数的“调用”实际返回一个generator对象:

def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return ‘done’

>>> g = fib(6)
>>> g
<generator object fib at 0x1022ef948>

迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

你可能会问,为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:pass

实际上完全等价于:

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:try:# 获得下一个值:x = next(it)except StopIteration:# 遇到StopIteration就退出循环break

总结

reference

稳扎稳打学Python!_那些疯狂到以为自己可以改变世界的人-CSDN博客

https://www.liaoxuefeng.com/wiki/1016959663602400/1017323698112640

Python生成器与迭代器相关推荐

  1. python生成器和迭代器作用_浅谈Python中的生成器和迭代器

    迭代器 迭代器协议 对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么返回一个异常来终止本次迭代.(只能往前走,不能往后退!) 迭代器对象 遵循了(实现了)迭代器协议的对象.(对象内 ...

  2. 详解 Python 生成器与迭代器 及其区别

    前言 不论是初学python还是python进阶,这都是绕不开的知识点,生成器与迭代器的概念相较于其他基础概念显得晦涩难懂,知识点囊括很多方面,查阅越多的资料,头就越大,现在这加以理解归纳总结. 相关 ...

  3. Python生成器、迭代器

    Python生成器.迭代器 一.生成器(generator) 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的 ...

  4. 彻底理解Python生成器和迭代器

    目录 1.列表生成式 2.生成器 3.迭代器 4.对yield的总结 5.补充:itertools库学习 1.列表生成式 首先举个例子 现在有个需求,看列表 [0,1,2,3,4,5,6,7,8,9] ...

  5. Python生成器与迭代器详细教程

    一.列表生成器 首先举个例子 现在有个需求,看列表 [0,1,2,3,4,5,6,7,8,9],要求你把列表里面的每个值加1,你怎么实现呢? 方法一(简单): info = [0, 1, 2, 3, ...

  6. 没有5年测开经验,还真说不清Python生成器、迭代器、装饰器

    一.什么是生成器? 使用了yield函数 就被称之为生成器,生成器是一个返回迭代器的函数,说白了生成器就是迭代器,只能用于迭代操作. 不懂?没关系,下面就一个斐波那契数列为例来进行讲解: 依靠简单循环 ...

  7. python生成器和迭代器

    Python3迭代器和生成器 很多朋友在初次接触 python 的 迭代器 和 生成器 时,总是不理解 生成器 和 迭代器的作用 和它们之间的关系,今天笔者来详细的讲解一下. 知识点目录: 一.迭代器 ...

  8. python生成器与迭代器(配套相关案列解析用法)

    一.python生成器简介 在 Python 中,使用了 yield 的函数被称为生成器(generator).跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就 ...

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

    文章目录 前言 一.迭代器--从一个简单例子入手 1.1 实现__iter__成为迭代对象 1.2 通过实现__next__方法成为迭代器 二.生成器 -- 更加简单的迭代器 2.1来个简单例子 2. ...

最新文章

  1. WinDbg !locks 不可用的问题
  2. 网站标题如何设计才更有利于网站优化呢?
  3. 学典教育计算机二级,层次化分类的离线中文签名真伪鉴别方法-计算机工程与应用.PDF...
  4. objective-c 编程总结(第六篇)运行时操作 - 方法交换
  5. 工作196:注意接收数据的格式
  6. cortex-m3 操作模式 寄存器组 异常类型 堆栈 中断
  7. windows2003配置
  8. OpenGL基础15:输入控制
  9. Android之——图片的内存优化
  10. 1018. Binary Prefix Divisible By 5可被 5 整除的二进制前缀
  11. Wincc7.3安装说明
  12. Java、JSP网上零食销售系统的设计与实现
  13. 星舆科技北斗高精度定位网启动北斗三号服务
  14. 基于地图开发控件GMap.Net 使用 (六) 中文显示详细街道数据信息
  15. 【写论文技巧】如何写一篇好论文?
  16. 2020-02-23
  17. 《软技能,代码之外的生存指南》--教你如何当一名程序员
  18. CentOS安装星际译王
  19. 大视频,经典电影想与海外亲人共享吗?酷达为您解难题
  20. html js滚轮事件,Js滚轮事件

热门文章

  1. 可编程并行通信接口8255A
  2. 最近整理的一些常见的面试题,面试大全,黑马程序员面试宝典题库---框架--篇
  3. Maven进阶(高级部分)
  4. 信号强度从百分比到分贝的转换
  5. v2ray本机和服务器连不上报错ocks: failed to transport all TCP response > io: read/write on closed pipe
  6. CSS画等腰三角形与直角三角形
  7. Codeforce 1296 E String Coloring
  8. 活动策划书用什么计算机软件,各行业主流设计软件有哪些?(设计人员请进)...
  9. ios截屏功能html,滚动截屏APP - iPhone上的长截图工具
  10. 金蝶K3开发-基础资料插件开发