生成器詳解

生成器(generator)

什麼是生成器

生成器是一種特殊的迭代器,生成器實現了迭代器協議__iter__(),__next__()python

生成器解決什麼問題

若是有一億的數據要咱們處理,咱們經過列表的方式來訪問的話,這一億的數據是存放在內存的,這樣會很是的消耗內存的,可是若是咱們使用生成器的話,每當處理一個數據的時候,內存中只是至關於存了一個數據,這樣能夠節省大量的內存函數

簡單案例

當生成器對象__next__()的時候,生成器函數會執行到下一個yield,並會返回一個參數code

例一協程

def zx():
    yield 1
    print(1)

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

例二對象

觸發StopIteration異常的兩種方式內存

1.迭代完最後一個元素後,觸發StopIteration異常generator

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的值,會成爲異常的說明值,如例子的2it

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__()生成的io

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

生成器的建立方式相似生成對象的方式ast

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

斐波那契數列

def zx(n):
    z,x=0,1
    while x < n:
        yield x
        z,x = x,z+x
z=zx(10)
for i in z:
    print(i)
相關文章
相關標籤/搜索