python中生成器的使用

水痕001發表於2018-12-12

python中我們常聽到迭代器和生成器,但是本人分開來介紹,只為告訴大家迭代器和生成器不是一個東西,在上篇文章中我們詳細的介紹過迭代器和可迭代物件,本章重點介紹生成器。

一、生成器的應用場景

對於呼叫一個普通的Python函式,一般是從函式的第一行程式碼開始執行,結束於return語句、異常或者函式所有語句執行完畢。一旦函式將控制權交還給呼叫者,就意味著全部結束。函式中做的所有工作以及儲存在區域性變數中的資料都將丟失。再次呼叫這個函式時,一切都將從頭建立。Python是通過生成器來實現類似於協同程式的概念:生成器可以暫時掛起函式,並保留函式的區域性變數等資料,然後在再次呼叫它的時候,從上次暫停的位置繼續執行下去。

二、一個最簡單的生成器

  • 1、使用列表推導式的方式生成一個生成器

    from collections.abc import Iterator, Iterableif __name__ == "__main__":    # 列表生成式    lis = [x * x for x in range(10)]    print(lis)    print(isinstance(lis, Iterable))    print(isinstance(lis, Iterator))    # 生成器    generator_ex = (x * x for x in range(10))    print(generator_ex)    print(isinstance(generator_ex, Iterable))    print(isinstance(generator_ex, Iterator))    print(next(generator_ex))複製程式碼
  • 2、從上面我們可以知道生成器是迭代器,具有迭代器的可迭代和**使用next()**函式的功能。記住:生成器是一種特殊的迭代器

三、為什麼要使用生成器函式,而不是直接使用函式

  • 1、通過列表生成式可以直接建立一個列表,但是受到記憶體的限制,可能建立一個很大的空間,但是實際情況中用不到那麼多(在C語言中所謂的堆區,沒釋放)
  • 2、生成器(generator)的定義就是根據列表元素可以動態的分配記憶體空間
  • 3、在實際開發過程中,如果我們要讀取一個十幾G大的檔案,如果是直接使用檔案開啟的方式,其實底層的全部載入在記憶體中,這樣造成計算機記憶體消耗,造成計算機卡死的局面,如果我們使用生成器,把大檔案做成文件碎片的方式,每次從中間讀取一點出來,然後再釋放記憶體,這樣就不會對計算機造成卡死的局面。

四、建立生成器函式

  • 1、將普通函式的return改為yield就是一個生成器函式

    def func():    print('====>
    first'
    ) yield 1 print('====>
    second'
    ) yield 2 print('====>
    third'
    ) yield 3 print('====>
    end'
    )if __name__ == '__main__': g = func() print(g) # 生成器是一種特殊的迭代器,具有可迭代屬性 for item in g: print(item)複製程式碼

五、協同程式

協同程式(協程)一般來說是指這樣的函式

  • 1、彼此間有不同的區域性變數、指令指標,但是共享全域性變數
  • 2、可以方便的掛起、恢復,並且有多個入口點和出口點
  • 3、多個協同程式間表現為協作執行,如A的執行過程中需要B的結果才能繼續執行。

幾個方法的介紹

  • 1、send(value):

    send()是除了next外另一個恢復生成器的方法,或者叫往生成器中傳遞引數的方法。是將yield語句變成了yield表示式,這意味著yield現在可以有一個值,而這個值就是在生成器的send方法被呼叫從而恢復執行時,呼叫send方法的引數。

    def test():    i = 1    while i <
    5: temp = yield i ** 2 print('temp', temp, '當前i=', i) i += 1 if __name__ == "__main__": t = test() print(next(t)) print(next(t)) print(t.send('hello')) print(t.send('word'))複製程式碼
    # 執行結果1         # 在main中列印的temp None 當前i= 1      # 在test函式中列印的4       # 在main中列印的temp hello 當前i= 2     # 在test函式中列印的9       # 在main中列印的temp word 當前i= 3      # 在test函式中列印的16       # 在main中列印的複製程式碼
    • 呼叫send傳入非None值前,生成器必須處於掛起狀態,否則將丟擲異常
    • 第一次呼叫next的時候 yield 1**2,返回是1,當時temp沒有傳遞值是None
    • 第二次呼叫next的時候 yield 2**2返回是4,當時temp沒有傳遞值是None
    • 第三次呼叫send傳送資料,傳送了hello當時temp=word,列印出temp的值,yield 3**2返回是9
    • 第四次和第三次一樣的
  • 2、close方法

    這個方法用於關閉生成器。對關閉的生成器後再次呼叫nextsend將丟擲StopIteration異常

六、yield from的使用

yield fromPython3.3 後新加的語言結構。yield from的主要功能是開啟雙向通道,把最外層的呼叫方法與最內層的子生成器連線起來。這兩者就可以進行傳送值和返回值了,yeild from結構的本質是簡化巢狀的生產器,不理解這個是什麼意思的話,下面我將用幾個例子來對其使用方法進行講解

一般場景使用方式

def gene():    for c in 'AB':        yield c  # 遇到yeild程式返回迴圈,下次從yeild後面開始。    for i in range(3):        yield iif __name__ == "__main__":    print(list(gene()))  # list內部會預激生成器複製程式碼

使用yield..from的時候

def gene1():    yield from 'ab'    yield from range(3)if __name__ == "__main__":    print(list(gene1()))   複製程式碼

來源:https://juejin.im/post/5c109a97e51d454f920a5380

相關文章