1. 程式人生 > >Python yield的功能淺析

Python yield的功能淺析

yield的功能類似於return,但是不同之處在於它返回的是生成器

生成器

生成器是通過一個或多個yield表示式構成的函式,每一個生成器都是一個迭代器(但是迭代器不一定是生成器)。

如果一個函式包含yield關鍵字,這個函式就會變為一個生成器。

生成器並不會一次返回所有結果,而是每次遇到yield關鍵字後返回相應結果,並保留函式當前的執行狀態,等待下一次的呼叫。

由於生成器也是一個迭代器,那麼它就應該支援next方法來獲取下一個值。

基本操作

        for item in items:
            div=item.find('a').attr('href')
            info=item.find('a').text()
            yield div,info
            # return {
            #     'div': div,
            #     'info ': info
            # }

返回迭代器,然後 使用for迴圈輸出

# 通過`yield`來建立生成器
def func():
   for i in xrange(10);
        yield i

# 通過列表來建立生成器
[i for i in xrange(10)]
# 呼叫如下
>>> f = func()
>>> f # 此時生成器還沒有執行
<generator object func at 0x7fe01a853820>
>>> f.next() # 當i=0時,遇到yield關鍵字,直接返回
0
>>> f.next() # 繼續上一次執行的位置,進入下一層迴圈
1
...
>>> f.next()
9
>>> f.next() # 當執行完最後一次迴圈後,結束yield語句,生成StopIteration異常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> 

除了next函式,生成器還支援send函式。該函式可以向生成器傳遞引數。

>>> def func():
...     n = 0
...     while 1:
...         n = yield n #可以通過send函式向n賦值
... 
>>> f = func()
>>> f.next() # 預設情況下n為0
0
>>> f.send(1) #n賦值1
1
>>> f.send(2)
2
>>> 

應用

最經典的例子,生成無限序列。

常規的解決方法是,生成一個滿足要求的很大的列表,這個列表需要儲存在記憶體中,很明顯記憶體限制了這個問題。

def get_primes(start):
    for element in magical_infinite_range(start):
        if is_prime(element):
            return element

如果使用生成器就不需要返回整個列表,每次都只是返回一個數據,避免了記憶體的限制問題。

def get_primes(number):
    while True:
        if is_prime(number):
            yield number
     number += 1

yield常見用法:該關鍵字用於函式中會把函式包裝為generator。然後可以對該generator進行迭代: for x in fun(param).

按照我的理解,可以把yield的功效理解為暫停和播放。

在一個函式中,程式執行到yield語句的時候,程式暫停,返回yield後面表示式的值,在下一次呼叫的時候,從yield語句暫停的地方繼續執行,如此迴圈,直到函式執行完。

擴充套件:

next函式與send函式很相似,都能獲得生成器的下一個yield後面表示式的值,不同的是send函式可以向生成器傳參。

yield from:封裝包含yield的函式,使得子函式也為一個generator.