生成器详解

Posted zx125

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了生成器详解相关的知识,希望对你有一定的参考价值。

生成器(generator)

什么是生成器

生成器是一种特殊的迭代器,生成器实现了迭代器协议__iter__(),__next__()

生成器解决什么问题

如果有一亿的数据要我们处理,我们通过列表的方式来访问的话,这一亿的数据是存放在内存的,这样会非常的消耗内存的,但是如果我们使用生成器的话,每当处理一个数据的时候,内存中只是相当于存了一个数据,这样可以节省大量的内存

简单案例

当生成器对象__next__()的时候,生成器函数会执行到下一个yield,并会返回一个参数

例一

def zx():
    yield 1
    print(1)

if __name__ == '__main__':
    zx=zx()
    data=zx.__next__()
    print(data)
1

例二

触发StopIteration异常的两种方式

1.迭代完最后一个元素后,触发StopIteration异常

def zx():
    yield 1
    print(1)

if __name__ == '__main__':
    zx=zx()
    data=zx.__next__()
    data=zx.__next__()
1
Traceback (most recent call last):
  File "C:/Users/Administrator/Desktop/01python/研究/生成器/t1.py", line 8, in <module>
    data=zx.__next__()
StopIteration

2.运行生成器函数的时候遇到return,return的值,会成为异常的说明值,如例子的2

def zx():
    yield 1
    return 2
    print(1)
    yield 3

if __name__ == '__main__':
    zx=zx()
    data=zx.__next__()
    data=zx.__next__()
Traceback (most recent call last):
  File "C:/Users/Administrator/Desktop/01python/研究/生成器/t1.py", line 10, in <module>
    data=zx.__next__()
StopIteration: 2

迭代器对象和生成器的产生区别

迭代器对象是通过可迭代对象的__iter__()生成的

zx=[1,2,3,4,5,6,7,8,9]
z1=zx.__iter__()

生成器的创建方式类似生成对象的方式

def zx():
    for i in range(10):
        yield i
z1=zx()

send方法

协程的实现主要就是靠的生成器的send方法

例子1-错误使用

def dog():
    print('小乌')
    while True:
        food = yield
        if food == '骨头':
            yield '好吃'
        else:
            yield '旺旺旺'
xw = dog()    #只是用于返回一个生成器对象,函数并不会执行下去
print(xw.send('骨头'))

出现错误,不能给刚创建的生成器发送非空的值

Traceback (most recent call last):
  File "C:/Users/Administrator/Desktop/01python/研究/生成器/t5_send.py", line 10, in <module>
    print(xw.send('骨头'))
TypeError: can't send non-None value to a just-started generator

报错信息说不能发送非空的值,那我们来试试发送一个None会发生什么

print(xw.send(None))

执行成功了

小乌
None

其实也可以用__next__()也能做到这个打印结果

print(xw.__next__())

结果一样

小乌
None

结论

1.__next__()的效果其实和send(None)一样

2.yield默认返回None

例子2-正确使用

def dog():
    print('小乌')
    while True:
        food = yield
        if food == '骨头':
            yield '好吃'
        else:
            yield '旺旺旺'
xw = dog()    #只是用于返回一个生成器对象,函数并不会执行下去
print(xw.__next__())
print(xw.send('骨头'))

结果

小乌
None
好吃

结论

1.当生成器刚创建完成,第一次使用先next或者send(None),不能直接send(非空参数)

2.send()有给yield的赋值功能

总结

1.__next__()的效果其实和send(None)一样

2.当生成器刚创建完成,第一次使用先next或者send(None),不能直接send(非空参数)

3.send()方法就相当于__next__()和赋值功能的结合

生成器实现计数器和协程

计数器

def jishu():
    i = 0
    while True:
        zx = yield i
        if zx == "按一下":
            i+=1
        elif zx == "重置":
            i=0
js=jishu()
print(js.__next__())
print(js.send("按一下"))
print(js.send("按一下"))
print(js.send("按一下"))
print(js.send("按一下"))
print(js.send("重置"))
print(js.send("按一下"))
print(js.send("按一下"))
0 初始化
1 按一下
2
3
4
0 重置
1
2

协程

吃包子

def consumer(name):
    print(f"name老板上包子")
    while True:
        baozi = yield
        print(f"name:吃了baozi")

def producer():
    for i in range(2):
        print('厨师做了两个包子')
        c1.send(f"肉包i")
        c2.send(f"菜包i")

c1 = consumer("小黄")
c2 = consumer("小乌")
c1.__next__()
c2.__next__()

producer()
小黄老板上包子
小乌老板上包子
厨师做了两个包子
小黄:吃了肉包0
小乌:吃了菜包0
厨师做了两个包子
小黄:吃了肉包1
小乌:吃了菜包1

以上是关于生成器详解的主要内容,如果未能解决你的问题,请参考以下文章

MybatisPlus的代码生成器 使用详解(整合springboot)

MybatisPlus的代码生成器 使用详解(整合springboot)

MybatisPlus的代码生成器 使用详解(整合springboot)

mybatis代码生成器配置文件详解

Python 3 之 生成器详解

代码详解生成器迭代器