1. 什麼是yield程序員
在介紹yield語法以前,首先要向你們說明Python中的迭代(iteration)、可迭代(iterable)、迭代器(iterator)以及生成器(Generator)的概念:面試
迭代是一種對數據的操做,例如針對一個list逐一獲取其中的元素的過程就叫作迭代。而可迭代是對象的一種特性,迭代操做只能針對擁有可迭代特性的對象進行,常見的可迭代對象包括數組、元組、字典等數據集合,下面代碼給你們演示了一個基本的迭代過程:算法
迭代器也是一種可迭代對象,與普通的可迭代對象的區別在於,迭代器內部實現了next函數用來生成每次迭代循環須要返回的元素。而最後的生成器則又是一種特殊的迭代器,具體體現上就是使用yield語法的函數,講到這裏就提到了yield語法,總的來講yield就是用來產生一個生成器的語法,例如將上述的迭代過程修改成生成器方式能夠這樣寫:數據庫
迭代器也是一種可迭代對象,與普通的可迭代對象的區別在於,迭代器內部實現了next函數用來生成每次迭代循環須要返回的元素。而最後的生成器則又是一種特殊的迭代器,具體體現上就是使用yield語法的函數,講到這裏就提到了yield語法,總的來講yield就是用來產生一個生成器的語法,例如將上述的迭代過程修改成生成器方式能夠這樣寫:數組
上述代碼的my_generator()即返回了一個生成器對象,每次循環時執行到yield處即返回當時的index的值,到下一次循環時將從上次返回的yield處繼續執行,直到index的值不知足小於5的條件時結束整個函數,此時也結束了對這個生成器的迭代過程。函數
這四者之間的關係可能會稍微有些混亂,再給你們簡單的總結一下:生成器是一種特殊的迭代器,而迭代器又是一種特殊的可迭代對象,可迭代對象就是能夠執行迭代操做也就是能夠經過for循環來遍歷的對象。學習
本文福利:私信小編【PDF】可獲取小編精心整理的電子書一套測試
2. 爲何要使用yield3d
看了上述兩個迭代過程,你們可能有些疑問,使用yield改形成生成器方式的代碼看起來比簡單的迭代一個列表的方式要複雜許多,那麼這樣寫有什麼優點呢?視頻
首先,使用yield語法的生成器最主要的一個優點就是極其省內存。例如上述兩個迭代過程,一樣是遍歷輸出0-4這幾個元素,使用列表的方式須要構建出一個長度爲5的數組並存儲在內存中,而使用生成器的方式只須要一個index變量便可實現,這仍是迭代元素較少的狀況下,若是迭代的是100萬甚至1000萬個元素時,列表的方式就須要構建一個長度爲100萬或者1000萬的數組,這時對於內存的使用就是很是大的負擔了,而使用生成器的方式,不管是迭代100萬仍是1000萬個元素,依然只須要一個index變量便可實現。
而且生成器的方式是即用即計算的,即迭代到對應的元素時,這個元素才相應的計算生成出來,而列表的方式須要在迭代開始前就構建出整個迭代數組,這在某些狀況下能夠極大地節省計算時間。例以下面這段代碼:
.在學習中有迷茫不知如何學習的朋友小編推薦一個學Python的學習q u n 227 -435- 450能夠來了解一塊兒進步一塊兒學習!免費分享視頻資料
這段代碼中,實際的迭代過程只進行到第10個元素即退出了整個循環,可是在迭代開始前,依然要計算1000萬次來生成迭代列表,這就形成了大量的計算和內存資源。而若是經過生成器重寫該迭代過程的話:
生成器在迭代開始前並不會計算出全部須要迭代的值,只有用到時纔會計算相應的值並返回,所以上述代碼的index將只會計算到10即結束了整個迭代過程,避免了計算和內存資源的浪費。
3. yield語法示例1:DIY一個range函數
Python自帶的range函數能夠產生一個可迭代對象,經常使用於for循環中,在Python 2中range函數生成的是一個列表,而在Python 3中range函數生成的是一個生成器。如今讓咱們來經過yield語法DIY一個本身的range生成器吧!
咱們首先構造一個返回給定範圍數組的函數:
這個函數接受兩個int類型的參數,分別爲數組的開始和結束,每一個數之間間隔爲1,咱們還能夠經過增長一個參數來指定兩個數之間的間隔,實現函數更高的靈活性:
咱們先來運行測試一下這個range函數:
上述代碼的輸出結果以下:
2
4
6
輸出結果符合咱們的預期,如今經過yield語法來將咱們本身DIY的range函數改形成一個生成器:
改造起來也很是簡單,首先將定義的用來存儲迭代元素的列表刪除,而後將原來添加元素到列表中的代碼改形成yield start便可,這樣咱們就本身DIY了一個簡易的、基於生成器實現的range函數。
4. yield語法示例2:讀取文件--《告白氣球》
生成器除了能夠用於計算生成數字元素外,在IO讀取方面也能起到很大做用,例如在讀取一個超大文件,或者查詢某個返回結果超多的數據庫時,使用經過yield語法構造的生成器來完成讀取操做能夠很大程度上下降程序對於內存的佔用。
例如咱們有一個名爲my_file.txt的文件,裏面存儲了周董的《告白氣球》的歌詞,如今咱們能夠經過yield語法來構造一個生成器用於一行一行的讀取每一句歌詞:
這裏使用with語法來讀取文件,這是Python 3推薦的方式。file.readline()函數每次返回一行內容,因爲返回的內容帶有每行結尾的換行符,所以經過line.strip(‘ ’)將換行符過濾掉。每次經過yield返回一行內容以後,再次經過file.readline()函數獲取下一行內容,直到整個文件被徹底迭代。
讓咱們來運行測試一下這個按行讀取文件內容的生成器:
上述代碼的輸出結果以下:
塞納河畔 左岸的咖啡
我手一杯 品嚐你的美
留下脣印 的嘴
……
《告白氣球》的歌詞就一行一行的輸出到屏幕上了,因爲歌詞行數過多,所以這邊只複製出前三行給你們演示結果。
5. yield語法示例3:斐波那契數列
斐波那契數列是一道經典的算法題,也是程序員面試時常常會被問到的一道題。斐波那契數列的就是一個形如1, 1, 2, 3, 5, 8, ……的數列,從第三項開始,每一項都等於前兩項之和。使用Python來實現一個計算斐波那契數列的典型函數以下:
這個函數經過一個名爲fib_list的數組存儲生成的前n個斐波那契數,最後一次性返回整個數組。其中a, b = b, a + b是Python的一個特點用法,用於快速交換兩個數,至關於:
參考以前DIY的range函數的寫法,將這個計算斐波那契數列的函數經過yield語法修改成生成器:
讓咱們來測試運行一下這個經過yield語法實現的斐波那契數列生成器:
對應的輸出結果爲:
1
1
2
3
5
能夠看到,從第三項開始的每一項都是前兩項的和,這樣的輸出結果就是咱們要的斐波那契數列。