生成器generator-python

1、定义

通过列表生成式(列表推导式),我们可以直接创建一个列表。但是受到内存限制,列表容量有限。但是如果列表元素可以按照某种算法推算出来,那么我们就可以在循环的过程中不断推算出后续的元素,而不必直接把全部元素放置在内存中。

在python中,这种一边循环一边计算的机制,称为生成器(generator)。

如果数据量比较大的情况下,生成器要比类别推导式节省大量内存空间。

2、创建

  • 方式1:通过推导式

    g = (x ** 2 for x in range(11))
    print(type(g))
    
  • 方式2:在函数中包含yield关键字,调用该函数就创建一个生成器对象。

    def generator_01():
        for i in range(11):
            yield i ** 2
    
    
    f = generator_01()
    print(type(f))
    

3、访问

如何访问生成器中的元素呢?

  • 访问方式1:生成器.__next__()

  • 访问方式2:next(生成器)

  • 访问方式3:生成器.send(参数) ,在标题4中讲解

  • 示例:

    def generator_01():
        for i in range(11):
            yield i ** 2
    
    
    f = generator_01()
    print(type(f))
    print(f.__next__())
    print(next(f))
    

显然这样每次调用只能访问一个元素,那么当生成器为有限元素时,访问到最后一个元素后再次调用会发生什么呢?

0
1
  File "F:/PycharmProjects/python-study/base/generator/test01.py", line 15, in <module>
4
    print(next(f))
StopIteration

程序会抛出StopIteration异常,那么我们通过for循环和异常处理,就可以访问全部元素。

  • 示例:打印含有n项的斐波那契数列

    def fib(n):
        '''
        包括指定项的斐波那契数列
        :param n: 项数
        :return:  斐波那契数列生成器
        '''
        n1 = 1
        n2 = 1
        len = 0
        while len < n:
            yield n1
            n1, n2 = n2, n1 + n2
            len += 1
    
    
    f = fib(6)
    while True:
        try:
            print(next(f))
        except StopIteration as e:
            print('访问结束')
            break
    

4、yield和send

下面我们通过程序断点看下yield执行顺序以及yield表达式及赋值问题。示例:

def gen():
    i = 0
    while i < 5:
        temp = yield i
        print('temp:', temp)
        i += 1

    return '没有值了'


g = gen()
for i in g:
    try:
        print(i)
    except StopIteration as e:
        print(e.value)

在这里插入图片描述

  • 图示,当程序执行进入gen()函数后,由第4行直接转到第12行,
  • 当程序再次进入gen()时,直接进入第4行。
  • 循环执行上面步骤。
  • yield作用:当程序执行到yiled时,计算yield表达式的值返回并记录返回位置,下次迭代从此继续执行
  • temp的打印值全部为:None,当继续执行yield表达式之后的赋值时,并没有值可用所以是None

那么怎么给yield表达式左边的变量赋值呢?此时需要用到send方法。

def gen():
    i = 0
    while i < 5:
        temp = yield i
        print('temp:', temp)
        i += 1

    return '没有值了'


g = gen()
print(g.send(None))
print(g.send('呵呵'))
print(g.send('hello'))

# 打印结果
0
temp: 呵呵
1
temp: hello
2
  • send第一次调用参数需要指定为None,因为第一次迭代执行到yield表达式就暂停了并不会给变量赋值

5、总结

  1. 生成器(generator)能够迭代的关键是它有一个next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常。
  2. 带有 yield 的函数不再是一个普通函数,而是一个生成器generator。可用next()调用生成器对象来取值。next 两种方式 t.next() | next(t)。
  3. 可用for 循环获取返回值(等后面讲解迭代器和可迭代对象时详细讲解): 每执行一次,取生成器里面一个值,基本上不会用next()来获取下一个返回值,而是直接使用for循环来迭代。
  4. yield相当于 return 返回一个值,并且记住这个返回的位置,下次迭代时,代码从yield的下一条语句开始执行。
  5. send() 和next()一样,都能让生成器继续往下走一步(下次遇到yield停),但send()能传一个值,这个值作为yield表达式整体的结果
  6. 生成器应用场景-协程,后面关于多线程协程的时候会讲解

参考博客地址:

参考视频地址:

  • https://www.bilibili.com/video/BV1R7411F7JV

源代码仓库:https://gitee.com/gaogzhen/python-study

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gaog2zh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值