彻底理解Python中的yield(111)

没有用过的东西,没有深刻理解的东西很难说自己会,而且被别人一问必然破绽百出。虽然之前有接触过python中的生成器的概念,但是只是走马观花,这两天的一次交谈中,别人问到了生成器,顿时语塞,死活想不起来曾经看过的东西,之后突然想到了yield,但为时已晚,只能说概念不清,所以本篇今天总结缕缕python的生成器和yield关键字。

在介绍yield前有必要先说明下Python中的迭代器(iterator)和生成器(constructor)。

一、迭代器(iterator)

在Python中,for循环可以用于Python中的任何类型,包括列表、元祖等等,实际上,for循环可用于任何“可迭代对象”,这其实就是迭代器。迭代器是一个实现了迭代器协议的对象,Python中的迭代器协议就是有next方法的对象会前进到下一结果,而在一系列结果的末尾是,则会引发StopIteration。任何这类的对象在Python中都可以用for循环或其他遍历工具迭代,迭代工具内部会在每次迭代时调用next方法,并且捕捉StopIteration异常来确定何时离开。

使用迭代器一个显而易见的好处就是:每次只从对象中读取一条数据,不会造成内存的过大开销。

二、生成器(constructor)

生成器函数在Python中与迭代器协议的概念联系在一起。简而言之,包含yield语句的函数会被特地编译成生成器。当函数被调用时,他们返回一个生成器对象,这个对象支持迭代器接口。函数也许会有个return语句,但它的作用是用来yield产生值的。

不像一般的函数会生成值后退出,生成器函数在生成值后会自动挂起并暂停他们的执行和状态,他的本地变量将保存状态信息,这些信息在函数恢复时将再度有效。

觉得还是模糊话,就拿我最近爬取3D彩票14的数据来说吧,如下图:

解析获取到一页信息后,我们需要将信息处理一下,遍历提取结果并生成字典,这样的目的是为了将数据结构整齐(不然的话,数据比较乱),便于后面存储数据。

在这里,我用了生成器函数,每调用一次函数时,将会返一个迭代对象,这个迭代对象里面包含一页的所有信息,如下图:

这样,在我们需要将信息保存时,只需再次遍历这个迭代对象,就可以一条一条的将每一期的3D彩票信息按照自己想要的结构存储起来,代码如下(我是将信息存储到Excel表格中):

保存效果:

分析一下这个例子:

parse_one_page函数中出现了关键字yield,预示着这个函数每次只产生一个结果值,这个函数返回一个生成器(通过print(parse_one_page)输出可以看出来),用来产生连续的迭代对象

在创造生成器实例的时候,只需要像普通函数一样调用就可以,但是这个调用却不会执行这个函数,这个可以通过输出看出来

看到这里应该可以理解生成器这个抽象的概念了吧,如果不懂可以留言,我会一一给大家回答

为什么叫生成器函数?

因为他随着时间的推移生成了一个数值队列。一般的函数在执行完毕之后会返回一个值然后退出,但是生成器函数会自动挂起,然后重新拾起继续执行,他会利用yield关键字关起函数,给调用者返回一个值,同时保留了当前的足够多的状态,可以使函数继续执行。生成器和迭代协议是密切相关的,可迭代的对象都有一个__next()__成员方法,这个方法要么返回迭代的下一项,要么引起异常结束迭代。

为了支持迭代协议,拥有yield语句的函数被编译为生成器,这类函数被调用时返回一个生成器对象,返回的对象支持迭代接口,即成员方法__next()__继续从中断处执行执行。

为了更加深刻的理解,我再举个例子:

结果如下:

正所谓,眼看十遍不如手动一遍,赶紧动起手来感受一下这个神奇又抽象的生成器概念吧;若你有更好的理解方式,欢迎留言分享

来源|恋习Python(ID:sldata2017)

此条目发表在杂七杂八分类目录,贴了, 标签。将固定链接加入收藏夹。