技术 | Python从零开始系列连载(十九)

生成器

还记得在迭代器里我们说为什么将列表转为迭代器么?

小明:因为列表太大的话占用内存太大,做成迭代器可以节省空间,用的时候再拿出部分

是的,今天要讲的生成器是不会把结果保存在一个系列中,而是保存生成器的状态。

在每次进行迭代时返回一个值,直到遇到StopIteration异常结束。

见过这种东西吧:

你可以认为每一杯饮料就是一个生成的对象,我不会一次倒出所有的饮料

而是要喝的时候去倒出一杯(也就是需要的时候生成一个)

1

简单方法创建生成器

我们看个例子:

我们发现,当要生成的list非常大时,抛出异常,存储报错。

那怎样生成这种巨大的list呢?

你亲手试一下,发现瞬间程序就运行结束了

我们看到,b是一个generator,也就是生成器模式

你应该已经注意到,生成器的创建很简单,将列表生成式的中括号改成小括号即可

注意:这里说的不是列表,因为列表的中括号改成小括号是元组!

那我们怎么生成一个内容呢?

和之前的迭代器相同,使用next()函数即可:

直到最后会抛出异常,也就是到达了生成器的末端了

2

函数进化为生成器

还记得函数的定义么?

我们在之前用递归定义了一个斐波那契数列

现在我们定义一个新的函数来生成斐波那契数列的第n项

为了实现后一项等于前两项之和使用了a,b = b,a+b

为什么这样写,留给大家思考~

提示:可以输入n=3,自己感受一下调用函数过程中a和b的变化

值得注意的是,这个函数,当n=0时返回的是1,而不是正确的0

所以我们对其进行修改:

在循环之前,加了一个判断

小明:老湿!你这个说的还是函数啊,和生成器有啥关系?说好的函数进化成生成器呢?

好的,我们看看函数怎么进化为生成器!

我们把函数中的return换成yield

函数就进化成了生成器,当我们调用时,发现返回的是生成器对象

为了拿到数据,我们应该怎么做呢?

小红:老师,是不是可以试试next()函数呢?

对,不过在此之前,我们先要用一个变量去接收这个生成器对象

并且为了观察生成器的特点,我们对函数进行修改!

仔细看好:

当我们使用next(a)对生成器操作一次时,会返回循环一次的值

也就是在yield处结束本次运行

但它的特点就是下次使用next(a)时,接着上次的断点继续运行,直到下一个yield

不断使用next(a),直到运行到生成器结尾处,如下图:

可能你对他的运行过程还不是特别清晰

我们加上print输出来彻底搞懂他的运行过程:

发现每次返回值都是在yield的地方了吧~

小结:

  1. 讲了两种生成器创建方式
  2. 加了yield的函数就变成了生成器
  3. 要定义一个变量接收生成器的返回值
  4. 使用next()获取生成器每次返回的值,并且断点在yield处
  5. 下次使用next()从上次的断电往下执行,直到生成器末端(这里表现为循环结束)
  6. 生成器属于迭代器,所以肯定是可迭代对象啦~

3

使用for循环调用生成器

我们使用next()去遍历生成器的时候,我们不知道什么时候会结束

而结束后再使用next()会抛出异常

因为生成器属于迭代器

所以我们可以使用for循环去调用生成器

4

与next()等价的方式

5

send()强势入场

我们先看一个例子:

发现每次运行,除了返回下一个,还会打印出None

观察代码,注意 item = yield i 这句

首先执行等号右边的,yield返回,此时,返回生成器一个对象,并且中断

在下次使用 f.__next__( )时候,并没有传内容进去,所以可以认为yield i 这整个赋值给item的为None

所以item打印出为None

为了做个比较,引入send()

send()可以看做next()的增强版

除了可以使用next()功能

还能传入一个值到上次yield断开地方的整体表达式(这里传给是yield i)

send()的坑:

这是为什么呢?

6

send()退化为next()

小红:老师,我想了两天终于想到了!

哦?你说说

小红:因为 f.send()取生成器第一个对象,并且传入了一个参数‘Python’

但是,并没有变量去接收这个参数!所以报错了!

是的,之前我们的代码是这样的:

注意,我们调用第一个对象使用next,并没有传入参数!

而第二次使用send调用下一个对象时候,传入的参数相当于代替了yield i

也就是赋值给了item,所以没报错

小明:老湿,你说send是加强版的next,我想给send退化到next,可以么?

这个嘛,是可以的!小明你试试!

小明:大家都退后!我要装逼了!

小明:不传参数竟然不行!!!

小明啊,应该是这样的!

传入None才对!

小明:我不服!老湿,你说这生成器很厉害,具体有啥应用呢?学了没用岂不是很鸡肋?

这个嘛!其实是有用的,我先剧透一下!

7

多任务——协程

我们先介绍一下多任务

多任务处理是指用户可以在同一时间内运行多个应用程序,每个应用程序被称作一个任务

简单点说,就是

你现在可能边看这篇文章边听着音乐

而看文章是一个任务(这里的任务指正在做的事情)

听音乐也是一个任务

你同时在做这两件事

就是多任务啦

电脑和人还是不一样的

我们今天讲一下协程来完成多任务(之后还会讲到线程、进程来完成多任务)

考虑一个工厂流水线

A机器每次将一件货物放入箱子

B机器每次将A机器的箱子封箱打包

为了不产生问题,必须A完成一个,B接着完成一个

并且看起来两个任务是同时执行的!

在Python中可以用生成器实现简单的协程:

我们来看这个程序,先定义了两个生成器(不是函数哦~原因在之前课程讲过)

当我们在while主程序中,先使用f1.__next__( )调用生成器func1,因为fun1的循环条件始终为真

所以先打印(执行装入操作)然后遇到 yield 退出生成器func1,回到主程序

接着执行f2.__next__( )调用生成器func2,像之前调用func1一样,先打印(执行打包操作)

然后遇到yield退出生成器func2,回到主程序

因为主程序循环条件始终为真,所以继续像之前一样,接着使用f1.__next__( )调用生成器func1。。。

如此往复。。。

我是使用打断来停止程序执行的,不然会不断执行下去

由于两个生成器(任务)交替执行,很快

就像在多任务执行

所以,通俗理解看上去同时执行的就是多任务~

小明:竟然有这种操作!

文章来源:Python爱好者社区

文章编辑:小柳

往期文章:

技术 | Python从零开始系列连载(十八)

技术 | Python从零开始系列连载(十七)

技术 | Python从零开始系列连载(十六)

技术 | Python从零开始系列连载(十五)

技术 | Python从零开始系列连载(十四)

技术 | Python从零开始系列连载(十三)

原文发布于微信公众号 - 灯塔大数据(DTbigdata)

原文发表时间:2018-06-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏阿凯的Excel

让你眼花缭乱的匹配函数反查技巧

小编已经连续写了三期关于匹配函数的用法,匹配函数的扛把子(老大)肯定是Vlookup函数莫属,但是Vlookup函数有一个问题,就是要查找的内容,必须在查找内容...

30560
来自专栏WD学习记录

牛客网 合唱团

有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能...

19320
来自专栏aoho求索

由散列表到BitMap的概念与应用(三):海量数据处理

遍历文件a,对每个url求取hash(url)%1000,然后根据所取得的值将url分别存储到1000个小文件(记为a0,a1,…,a999,每个小文件约300...

14910
来自专栏木可大大

编写优雅代码的最佳实践

Robert Martin曾说过"在代码阅读中说脏话的频率是衡量代码质量额唯一标准"。同时,代码的写法应当使别人理解它所需的时间最小化,也就是说我们写的代码是给...

10220
来自专栏数据小魔方

左手用R右手Python系列——面向对象编程基础

面向对象编程是程序设计中一种重要且高效的编程规范,它区别于常见的面向过程编程。在R语言以及Python的程序包开发过程中,大量使用了面向对象的编程范式。 百度...

528120
来自专栏企鹅号快讯

30分钟学会用Python编写简单程序

参与文末每日话题讨论,赠送异步新书 异步图书君 学习目标 知道有序的软件开发过程的步骤。 了解遵循输入、处理、输出(IPO)模式的程序,并能够以简单的方式修改它...

697100
来自专栏java一日一条

成为优秀Swift开发者的10条建议

在这里给大家分享一些帮助大家成为更优秀的Swift开发者的建议,让你的代码,写的更少,性能更优 。

12420
来自专栏C语言及其他语言

[每日一题]C语言程序设计教程(第三版)课后习题5.7

题目描述 给出一个不多于5位的整数,要求 1、求出它是几位数 2、分别输出每一位数字 3、按逆序输出各位数字,例如原数为321,应输出123 输入 一个不大于5...

35770
来自专栏take time, save time

你所能用到的BMP格式介绍(二)

一、可能你忽视的基础         在正式开始之前,我不得不从最基本的地方开始,因为这些地方大多数人会忽视的一干二净,如果不在开始进行说明,那么在后面一定会有...

30370
来自专栏嵌入式程序猿

号外号外:无规矩不成方圆(4)

本文MISRA规则由嵌入式程序猿整理自网络,版权归原作者所有 不能使用三字母词 三字母词由2 个问号序列后跟1 个确定字符组成(如, ??- 代表“ ~”(非)...

27350

扫码关注云+社区

领取腾讯云代金券