最近身边的朋友都在问我迭代器是什么回事,经常跟大家一起讨论python的迭代器,一点点的我觉着自己有了更深一层的理解。我写下这篇文章,希望能对懵懵懂懂的好伙伴有些帮助~

我也不是什么能人,难免说错一些东西,我会认真的把自己理解的说明白,欢迎各路大神批评指正。

生成器是什么??哇!不到哇~~~(眩晕持续中。。。)

生成器: 生成器是一类特殊的迭代器。

  他是python提供给我们的一个功能,提供给我们快速简洁的编写迭代器的功能。

  当我们需要编写一个迭代器的时候,发现迭代器很麻烦,我们需要写__next__和__iter__两个方法:

    __iter__方法负责返回一个迭代器(在迭代器种返回自己,在可迭代对象中返回帮助自己迭代的迭代器)

    __next__方法做两件事:

  ·    1 如果当前要获取的元素没有超出界限,就返回当前元素,然后自己指向为下一个元素等待返回;

       2 如果上次反回了最后一个元素,这一次再调用next的时候已经没有元素了,就抛出StopIteration异常。

    这两个方法中与业务逻辑相关的在next里面,而且next里面抛出异常也与我们想要迭代的元素没有关系,我们写一个迭代器实际上是很麻烦的。

  在这种情况下,python提供给我们生成器的功能,通过实现一个生成器,我们只需要编写和业务逻辑有关的返回数据部分的代码,而next方法、iter方法和越界抛出异常全都由python帮助我们进行封装,不用我们操心了。这就是生成器!

  迭代器又是啥啊!!我去(- 。 -) 好委屈。 迭代器呢,我之前发过一篇博文,里面详细的分享了我对迭代器的理解。欢迎伙伴们参考~~ 也可以看其他大神的博文哦~一定要搞明白 迭代器是什么否则,生成器也搞不懂的呢!

OK!!下面我和大家来探讨一下生成器的实现~~~

生成器的实现:

  生成器有两种编写方法:

    1 ( ) 括号内 放入列表推倒表达式 返回一个生成器对象

    2 yield 关键字函数

  这两种方法怎么用呢!! 我们跟大家分享一下 嘻嘻~ 大家要认真读注释哦

1 ( ) 括号内 放入列表推倒表达式 返回一个生成器对象
# 1 ( 列表推导式 )
#生成前十个偶数的列表
list = [ x*2 for x in range(11) ]
print(list) #生成前十偶数的生成器
oddIterator=( x*2 for x in range(11))
print(type(oddIterator))
for num in oddIterator:
print(num,end=" ")
从代码种我们可以看出,普通的列表推导式,放到括号当中,接收的对象是一个生成器对象。
它也是一个迭代器对象,可以放到for循环当中操作,
也可以用next方法一个一个取出元素,还能看到当越界的时候抛出了StopIteration的异常
这些复杂的东西都被python帮我们封装了,不需要我们自己操心去处理了。 2 yield 关键字函数
这个概念有点头痛,这什么是yield关键字函数呢? 不知道呀~
请跟我一起理解:假如我们想写一个函数,这个函数的功能是:把传入参数n以内的偶数能给print出来。我们需要用到循环,设置一个临时变量i 从0自增2到n为止,每一次我们都print(i),这样我们就能在console中得到n以内的全部偶数。
现在我们更改需求,如果想获取n以内的偶数的生成器,我们把之前的print(i) 改成yield i ,这样就实现了这样功能的生成器。
先看一段代码!
# yield关键字函数

#这个函数的功能是输出了0到n的所有偶数
def odd(n):
for i in range(0,n+1,2):
print(i)
odd(10) #现在 我们把这个方法改成yield关键字函数的生成器
# 一个n以内偶数的生成器
def odd(n):
for i in range(0,n+1,2):
yield i
#用gen10获取一个生成器的对象
gen10 = odd(10)
# 把生成器对象放入for循环当中使用
for i in gen10:
print(i,end=" ")
从代码种我们可以看出,把我们平时想要得到的数据 用yield关键字声明一下,就可以得到生成器了。
python看到yield会把这个函数帮助我们继续封装,加上next方法和iter方法,并且看到越界后会帮助我们抛出异常。
这些复杂的与业务逻辑无关的已经无需我们编程者来操心了,python帮助我们完成了。
现在说一下yield i 这句话到底发生了什么:
首先获得了一个迭代器对象gen = odd(20)
当函数执行到yield i 的时候 实际上函数会把i的数值抛出来,我们调用next(gen)的时候获取了yield 后面的值,然后函数就会暂停,等待下一次再调用next(gen)的时候,函数从yield继续向下执行,直到遇到yield的时候又返回了i的值,然后函数再暂停,等待下一次唤醒。
这个循环一直做,到函数结束的时候,python帮助咱们抛出了异常。 yield关键字函数的扩展:
返回值:果我们的生成器yield关键字函数当中,结束时候自己设置了返回值,这个返回值会被抛出的异常接收,存到了异常对象的value属性里面。
两种唤醒方式:
1 next(gen) 之前讨论过,调用next后,函数从上一次抛出一个数据暂停之后继续执行,直到遇到yield时候抛出来i返回给next函数再暂停,等待下一次唤醒。
2 gen.send( mess ) 这个方法也能够唤醒生成器函数,并且得到新的yield抛出数据,不同点是:
如果我们 把上面的yield抛出改成 msg = yield i , 那么我们用send传入的mess将会在唤醒的时候被msg接收到。如果我们用next方法唤醒,则msg接收到None。 很晕是不是! 我们上一段代码理解一下:
 # yield关键字函数
#yield关键字函数的生成器
# 一个n以内偶数的生成器
def odd(n):
for i in range(0,n+1,2):
'''
代码的执行从右向左,当遇到yield的时候,会把i抛出给next的调用返回,然后函数停在这里
下一次外面调用next或者send方法唤醒的时候,msg = 开始执行,上一次停在了yield i 这里,左边还没执行
然后再碰到yield i 的时候把i抛出来再暂停。。。。。。
'''
msg = yield i
'''
当函数执行结束的时候python认为迭代器结束了,帮我们抛出异常,返回值会被异常对象接收存在了value属性里面
'''
return "哈哈哈"
#用gen获取一个生成器的对象
gen = odd(5) #生成器也是迭代器,用next方法唤醒yield暂停,继续向下执行
print( next(gen) )#
print( next(gen) )#
print( gen.send("传入数据") )#传入数据 4 这个时候 在函数里面会打印出来传入的 “传入数据”, 并返回了下一次的i 也就是4 然后暂停 #这时候不论next还是send,迭代器都已经结束了 python会帮我们抛出异常,函数的返回值会被异常对象接收存在value属性里
try :
print( next(gen) )
except StopIteration as e :
print(e.value) #会打印出 哈哈哈, 也就是odd函数的返回值

其实到这里 知识点就已经全部结束了。 我们再来总结一下:

生成器有两种实现方式:

  1 () 括号内 放入 列表生成式

  2 yield 关键字函数:正常写一个业务逻辑函数,把想迭代的数据用yield关键字声明。函数执行到yield关键字会把后面的数值抛出去,然后暂停,等待下一次唤醒。

    两种唤醒方式: gen = 生成器函数()   我们拿到一个生成器对象gen

          1 next(gen)  能够唤醒上一次暂停,函数会从上一次抛出数之后继续执行到再次遇见yield i 把i抛回来 后再暂停

          2 gen.send(mess) 唤醒上一次暂停,并且把mess传入给接收yield 的变量,让我年后函数继续执行遇到 msg = yield i  的时候把i抛出来返回,再暂停。

生成器实质: 它是python提供给我们快速写一个迭代器的功能。我们只关心业务逻辑,把功能实现了,至于迭代器内部的iter方法和next方法已经不用我们操心了,迭代过后的抛出异常也为我们封装好好了。 

  因为它会被封装成迭代器,所以我们可以把生成器对象放入for in 循环中,也可以用next() 方法去获取元素!!

OK啦!! 这些知识点晦涩难懂,如果读不懂的伙伴们,希望你们认真学习一些迭代器的知识,这样才能看懂生成器哦~~可以参考我之前的博文,也可以参考其他大神的博文哦~

谢谢观赏,希望对大家有帮助!么么哒~

嘻嘻

python当中的生成器的更多相关文章

  1. Python三大器之生成器

    Python三大器之生成器 生成器初识 什么是生成器 生成器本身属于迭代器.继承了迭代器的特性,惰性求值,占用内存空间极小. 为什么要有生成器 我们想使用迭代器本身惰性求值的特点创建出一个可以容纳百万 ...

  2. python高级之生成器&迭代器

    python高级之生成器&迭代器 本机内容 概念梳理 容器 可迭代对象 迭代器 for循环内部实现 生成器 1.概念梳理 容器(container):多个元素组织在一起的数据结构 可迭代对象( ...

  3. 【python】迭代器&生成器

    源Link:http://www.cnblogs.com/huxi/archive/2011/07/01/2095931.html 迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素 ...

  4. 第三篇:python高级之生成器&迭代器

    python高级之生成器&迭代器   python高级之生成器&迭代器 本机内容 概念梳理 容器 可迭代对象 迭代器 for循环内部实现 生成器 1.概念梳理 容器(container ...

  5. python当中的 可迭代对象 迭代器

    学习python有一段时间了,在学习过程中遇到很多难理解的东西,做一下总结,希望能对其他朋友有一些帮助. 完全是个人理解,难免有错,欢迎其他大神朋友们批评指正. 1 迭代 什么是迭代呢??我们可以这样 ...

  6. python中的生成器函数是如何工作的?

    以下内容基于python3.4 1. python中的普通函数是怎么运行的? 当一个python函数在执行时,它会在相应的python栈帧上运行,栈帧表示程序运行时函数调用栈中的某一帧.想要获得某个函 ...

  7. python记录_day12 生成器

    什么是生成器? 生成器的实质就是迭代器,我们能够从生成器中一个一的拿值 python中获取生成器的方式有三种: 1.通过生成器函数 2.通过生成器表达式 3.通过数据转换也可以获取生成器(某些对象执行 ...

  8. 十三. Python基础(13)--生成器进阶

    十三. Python基础(13)--生成器进阶 1 ● send()方法 generator.send(value) Resumes the execution, and "sends&qu ...

  9. 十二. Python基础(12)--生成器

    十二. Python基础(12)--生成器 1 ● 可迭代对象(iterable) An object capable of returning its members one at a time. ...

随机推荐

  1. 记录解决python在spark运行加载第三方库的问题

    一般写python的我们经常会import一些常用的库,然后有时集群环境上的python没有这些库,怎么办呢? 通过一段时间的摸索发现有二种方式可以解决这个问题: 第一种方法: 下载对应python的 ...

  2. JSP中动态include和静态include区别

    静态include(<%@ include file=""%>): 静态include(静态导入)是指将一个其他文件(一个jsp/html)嵌入到本页面 jsp的inc ...

  3. Mycat 分片规则详解--ER关系表分片

    ER模型是实体关系模型,基本元素是实体.关系和属性,Mycat 针对ER关系表的切分规则中,使得有相互依赖的表能够按照某一个规则切分到相同的节点上,避免垮库 Join 关系查询,下面的示例为订单(or ...

  4. 笔记:Struts 2.3.31 配置说明

    复制文件到站点的 WEB-INF\lib 目录,文件列表如下,黄色突出显示的是必须加入的核心包 struts2-core-2.3.31.jar:struts2 的核心库 xwork-core-2.3. ...

  5. struts2.0简单教程

    Struts2.0简单配置教程: 在Eclipse中配置Struts2 步骤一:首先打开java ee并建立一个动态网站项目,我建立的项目名为TestDemo,如下图: 建立之后可在左侧发现工程,展开 ...

  6. 关于mongodb按照字段模糊查询方法

    模糊查询:tname包含某个关键字测试' cd /opt/soft/mongodb/bin ./mongo --host 192.168.0.1  --port 17017  test db.test ...

  7. redis客户端可以连接集群,但JedisCluster连接redis集群一直报Could not get a resource from the pool

    一,问题描述: (如题目)通过jedis连接redis单机成功,使用JedisCluster连接redis集群一直报Could not get a resource from the pool 但是使 ...

  8. 关于JSP页面URL传值所遇到的小问题

    在JSP页面中我的页面传值加了分号,在后台取值是没有问题的. 但是在XML底层执行时就会返回不了值,这是什么原因呢? 经过努力排查发现了分号导致了${XXX}的值都成了和前面ID一样的串.去掉${XX ...

  9. Algorithm --> 全排列

    1.算法简述 简单地说:全排列就是从第一个数字起每个数分别与它后面的数字交换. E.g:E = (a , b , c),则 prem(E)= a.perm(b,c)+ b.perm(a,c)+ c.p ...

  10. ubuntu apt-get安装、卸载软件命令及如何查看日志

    linux亮红灯的我,开始学习linux,学习使我快乐,大家一起来学习... 1.安装软件命令 sudo apt-get apache2     安装apache,安装在默认路径下,指定路径安装,其实 ...