【python实用特性】- yield生成器

这个概念较难理解,我们可以通过解答以下几个问题来掌握它。
本节会用到可迭代对象列表生成式知识,建议先看下之前的文章进行了解。
【python实用特性】- 迭代、可迭代对象、迭代器
【python实用特性】- 列表生成式

1、什么是生成器?

生成器: 生成,很好理解,创建一个对象的意思。那是什么呢?器可以理解为工具的意思,所以生成器,就是按照一定规则,创建某种对象的工具。

2、为何要用生成器?有何好处?

举个简单的例子,我们要创建一个100个元素的列表。很简单,list(range(100)),那如果要创建一个100万、1000万元素的列表呢?
诚然,我们依旧可以使用list(range(10000*100)list(range(10000*1000)来达到目的。
但这样会带来几个问题:

  • 变量存储于内存中,所以列表长度受限于内存大小,是有限的
  • 列表需要将所有元素一次性创建完成后才能操作,数据过大时,内存使用会瞬间升幅,存在内存不足风险
  • 大多数时候只需要用到部分元素,这就造成了内存空间的浪费
    为了解决以上问题,于是引入了一种不用一次性全部生成,可以按需逐次获取数据的方案——生成器
    所以使用生成器的好处也很明显:
    (1)不用一次性生成所有数据,能有效节约内存
    (2)可以按需逐次获取数据,不会造成内存空间的浪费
3、python中如何实现生成器?

一般来说,python中的生成器有两种实现方式。

  • 普通实现
    将列表生成式的[]改为()即可,实例如下:

    g = (x for x in range(10))
    print(type(g)) #type查看g的类型
    from typing import Iterable
    print(isinstance(g,Iterable)) #判断是否是可迭代对象
    

    输出:

    <class 'generator'>
    True
    

    可见,此时的g便是一个生成器,同时也是一个可迭代对象!
    这意味着我们可以使用 next(g)进行 取值

  • yield实现
    实例如下,打印0~2

    #自然数生成器
    def getN(N):
        n = 0
        while n<N:
            yield n  #使用yield 返回数据
            n+=1
    g = getN(3)
    print(next(g))
    print(next(g))
    print(next(g))
    

    输出:

    0
    1
    2
    

    如上,我们在函数 getN(N)中使用了yield关键字返回数据,所以这个函数就变成了一个生成器。
    小结: 若一个函数中使用了yield返回数据,那这个函数就是一个生成器。

4、yield生成器的运行机制

通过上面的学习,我们已经知道如何去构造一个生成器。那它是如何运行的呢?又为何说它是逐次获取数据呢?
先看一个例子

def test():
    print('返回第一个数据:')
    yield 'data1'
    print('返回第二个数据:')
    yield 'data2'
    print('返回第三个数据:')
    yield 'data3'
g = test()
print(next(g))

输出:

返回第一个数据:
data1

可见,有三个yield 返回,但因为我们只使用了一次 next()函数,所以只打印了data1,第一个yield返回的数据。
那调用两次呢?

print(next(g))
print(next(g))

输出:

返回第一个数据:
data1
返回第二个数据:
data2

小结: 调用一次 next()函数,便执行一次生成器,遇到yield关键字后,将数据返回。之后生成器暂停运行,保存当前的运行状态,等待下一个next()调用。

5、使用循环来迭代生成器

上面的例子中,我们都是通过next()函数来取值。这种方式当数据量大了之后,就会变得很麻烦。所以需要使用更高效的方法,而因为生成器也是一个可迭代对象,所以我们可以使用循环来进行迭代。
打印0~2的实例改写如下:

  • while循环

    
    def getN(N):
        n = 0
        while n<N:
            yield n
            n+=1
    g = getN(10)
    while True:
        try:
            print(next(g),end='\t')
        except StopIteration:
            break #跳出循环
    

    注:使用while循环实现时,要用try...except捕获StopIterator异常。

  • for循环

    def getN(N):
        n = 0
        while n<N:
            yield n
            n+=1
    g = getN(3)
    for data in g:
        print(data)
    

    注:for循环会自动调用next()函数,且捕获异常。推荐使用。

博主其他系列文章:

[1] 【python实用特性】-切片

[2] 【python实用特性】- 迭代、可迭代对象、迭代器

[3] 【python实用特性】- 列表生成式

[4] 【python实用特性】- 装饰器

[5] Python如何爬取动态网页数据

[6] Python+selenium实现自动爬取实例

[7] python爬取豆瓣Top250-改进版

[8]【Scrapy爬取实例】- 爬取链家网指定城市二手房源信息

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值