天天看點

python yield 與 yield from

轉載至:https://blog.csdn.net/chenbin520/article/details/78111399?locationNum=7&fps=1

1、yield使用

1)函數中使用yield,可以使函數變成生成器。一個函數如果是生成一個數組,就必須把資料存儲在記憶體中,如果使用生成器,則在調用的時候才生成資料,可以節省記憶體。

2)生成器方法調用時,不會立即執行。需要調用next()或者使用for循環來執行。使用for循環不需要自己捕獲StopIteration異常。使用next()方法,當生産器方法執行結束會抛出StopIteration異常(隻要不是使用yield傳回資料,都會抛出StopIteration異常)。

示例:

def fib(max):
    n,a,b = ,,
    while n < max:
        yield b
        a, b = b, a+b
        n = n + 
    return 'done'

n = fib()
for n1 in n:
    print(n1)
           

3)yield不僅可以傳回值,也可以接收值。下面面示例為生産消費模式。生産者生産一條記錄,消費者消費一條記錄。

4)調用生成器send方法傳遞資料時,必須先調用next(c)或者c.send(None)方法,執行到yield語句,等待接收資料。否則會報錯。

以下代碼為廖雪峰網站的示例:

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432090171191d05dae6e129940518d1d6cf6eeaaa969000

def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'


def produce(c):
    c.send(None)  # 和next方法一樣 擷取下一個值,必須先使用None參數調用一次, 執行到yield
    n = 
    while n < :
        n = n + 
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)  # 先發送值給yield語句,再執行到yield語句時傳回
        print('[PRODUCER] Consumer return:%s' % r)
    c.close()

c = consumer()
produce(c)
           

2、yield from的使用

1)為了讓生成器(帶yield函數),能簡易的在其他函數中直接調用,就産生了yield from。

2)以下代碼,htest為生成器,itest通過yield from 直接調用htest。這樣itest也變成了一個生成器。建立itest執行個體不斷的去擷取資料,當生成器執行結束時,會抛出StopIteration異常。那這個異常是htest抛出的,還是itest抛出的。通過捕獲異常,會發現其實是itest抛出異常,htest并不會抛出StopIteration異常。

3)yield from 也可以傳回值,通過變量接收。變量接收的值,即htest使用return傳回的值。示例代碼中,當i==3時,會直接使用return傳回,這時val的值就是100;因為htest函數中不是使用yield傳回值,是以itest會繼續執行print(val)語句。itest代碼執行完,然而并沒有使用yield傳回資料(htest中沒有,itest中也沒有),是以馬上會抛出StopIteration異常)(如果在itest函數最後使用yield傳回一個資料,就不會抛出異常)。

def htest():
    i = 
    while i < :
        n = yield i
        if i == :
            return 
        i += 


def itest():
    val = yield from htest()
    print(val)

t = itest()
t.send(None)
j = 
while j < :
    j += 
    try:
        t.send(j)
    except StopIteration as e:
        print('異常了')
           

繼續閱讀