OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4184|回复: 0

浅析Python生成器(收藏防迷路)

[复制链接]

143

主题

145

帖子

0

精华

高级会员

Rank: 4

积分
585
金钱
585
注册时间
2020-5-25
在线时间
42 小时
发表于 2020-12-22 15:35:18 | 显示全部楼层 |阅读模式
1、什么是生成器
在介绍生成器之前,我们先来看一个简单的例子:创建一个列表,列表中存放[0, 9]范围内每个整数平方值
>>> L = [x * x for x in range(10)]>>> L[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
显然,通过列表生成式,很容易的创建了一个这样的列表。但是,我们想创建一个更大的列表,受内存的限制,列表的容量肯定是有限的。比如我们想创建一个包含10万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
有没有这样的一种机制呢?比如,列表中的元素可以按照某种算法推算出来,我们可以根据自己的需求去取,取的时候根据算法推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。我们今天的讲的生成器就实现了这种机制。
那什么是生成器呢?可以用一句话概括:在Python中,这种一边循环一边计算的机制,就是生成器(generator)。
2、生成器的创建
Python中要创建一个生成器,有很多种方法,先来看一下最简单的一种,只要把一个列表生成式中的[ ]换成(),返回的不再是一个列表,而是一个生成器对象。
>>> G = (x * x for x in range(10))>>> G<generator object <genexpr> at 0x0000000004CA8948>
那么如何根据生成器对象,获取其中的元素呢?
如果一个个的获取,可以通过next()函数获取generator中下一个元素
[url=][/url]
>>> next(G)0>>> next(G)1>>> next(G)4>>> next(G)9>>> next(G)16>>> next(G)25>>> next(G)36>>> next(G)49>>> next(G)64>>> next(G)81>>> next(G)Traceback (most recent call last):  File "<pyshell#24>", line 1, in <module>    next(G)StopIteration[url=][/url]

generator保存的是计算方法,每次调用next(G),就计算出G的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。 因此,在使用next函数获取generator中下一个元素,可以通过捕获异常来判断是否已经取到最后一个元素。
try:    next(G)except StopIteration:
  /* something hint is the last element */    pass

由于generator是可迭代对象,我们也可以通过for循环去获取generator中每一个元素
[url=][/url]
>>> G = (x * x for x in range(10))>>> for n in G:    print(n)    0149162536496481[url=][/url]

可以看出,通过for循环来迭代生成器对象,并不用关心StopIteration错误,使用for循环来迭代要比使用next函数要简单的多。
generator功能十分强大,也可以将一个函数变成生成器。如果,函数中包含yield关键字,那么这个函数就不是一个普通的函数,而是一个generator。
[url=][/url]
def sqr_calc(num):    i = 1    while num > 0:        result = i**2        yield result        i = i + 1        num = num -1    return 'done'[url=][/url]

这是generator的另一种写法, sqr_calc函数中包含yield关键字,这个函数就变成了一个generator,sqr_calc函数中包含了相关的元素的计算方法
[url=][/url]
>>> itr = sqr_calc(10)>>> print(itr)<generator object sqr_calc at 0x00000000051F1648>>>> for n in itr:     print(n)     149162536496481100[url=][/url]

调用sqr_calc函数,返回一个生成器对象,使用for循环,可以依次获取可迭代对象的下一个计算结果
3、生成器的原理
函数中有yield关键字,这个函数就变成了一个generator,它的执行流程和函数的执行流程就不同了。函数是顺序执行的,函数遇到return或执行到最后一句语句就返回。而变成generator的函数,在每次调用next函数的时候执行,遇到yield关键字时返回,再次执行时从yield后面的语句继续执行。
举例如下:
定义一个gene_test函数,函数中包含多个yield,可以看出改函数是一个generator
[url=][/url]
def gene_test():    print('step 1')    yield 1    print('step 2')    yield 2    print('step 3')    yield 3[url=][/url]

调用该gene_test时,首先要生成一个generator对象,然后用next()函数不断获取返回值
[url=][/url]
>>> gen = gene_test()>>> next(gen)step 11>>> next(gen)step 22>>> next(gen)step 33>>> next(gen)Traceback (most recent call last):  File "<pyshell#13>", line 1, in <module>    next(gen)StopIteration[url=][/url]

同样的,把函数改成generator后,我们基本上从来不会用next()函数来获取下一个返回值,而是直接使用for循环来迭代。
学习资料自取:
一小时全面认识Python爬虫开发
http://www.makeru.com.cn/live/detail/1637.html?s=143793
一节课快速认识人工智能必备语言:python
http://www.makeru.com.cn/live/detail/1635.html?s=143793
python零基础全套
http://www.makeru.com.cn/course/details/1804.html?s=143793

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-25 12:33

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表