當前位置:成語大全網 - 新華字典 - 閑話python 45: 淺談生成器yield

閑話python 45: 淺談生成器yield

生成器似乎並不是壹個經常被開發者討論的語法,因此也就沒有它的大兄弟叠代器那麽著名。大家不討論它並不是說大家都已經對它熟悉到人盡皆知,與之相反,即使是工作多年的開發者可能對生成器的運行過程還是知之甚少。這是什麽原因導致的呢?我猜想大概有以下幾點原因: (1)運行流程不同尋常,(2)日常開發不需要,(3)常常將生成器與叠代器混淆。 生成器的運行流程可以按照協程來理解,也就是說 返回中間結果,斷點繼續運行 。這與我們通常對於程序調用的理解稍有差異。這種運行模式是針對什麽樣的需求呢? 壹般而言,生成器是應用於大量磁盤資源的處理。 比如壹個很大的文件,每次讀取壹行,下壹次讀取需要以上壹次讀取的位置為基礎。下面就通過代碼演示具體看看生成器的運行機制、使用方式以及與叠代器的比較。

什麽是生成器?直接用文字描述可能太過抽象,倒不如先運行壹段代碼,分析這段代碼的運行流程,然後總結出自己對生成器的理解。

從以上演示可以看出,這段代碼定義了壹個函數,這個函數除了yield這個關鍵字之外與壹般函數並沒有差異,也就是說生成器的魔法都是這個yield關鍵字引起的。 第壹點,函數的返回值是壹個生成器對象。 上述代碼中,直接調用這個看似普通的函數,然後將返回值打印出來,發現返回值是壹個對象,而並不是普通函數的返回值。 第二點,可以使用next對這個生成器對象進行操作 。生成器對象天然的可以被next函數調用,然後返回在yield關鍵字後面的內容。 第三,再次調用next函數處理生成器對象,發現是從上次yield語句之後繼續運行,直到下壹個yield語句返回。

生成器的運行流程確實詭異,下面還要演示壹個生成器可以執行的更加詭異的操作:運行過程中向函數傳參。

返回生成器和next函數操作生成器已經並不奇怪了,但是在函數運行過程中向其傳參還是讓人驚呆了。 調用生成器的send函數傳入參數,在函數內使用yield語句的返回值接收,然後繼續運行直到下壹個yield語句返回。 以前實現這種運行流程的方式是在函數中加上壹個從控制臺獲取數據的指令,或者提前將參數傳入,但是現在不用了,send方式使得傳入的參數可以隨著讀取到的參數變化而變化。

很多的開發者比較容易混淆生成器和叠代器,而叠代器的運行過程更加符合壹般的程序調用運行流程,因此從親進度和使用熟悉度而言,大家對叠代器更有好感。比如下面演示壹個對叠代器使用next方法進行操作。

從以上演示來看,大家或許會認為叠代器比生成器簡單易用得太多了。不過,如果妳了解叠代器的實現機制,可能就不會這麽早下結論了。python內置了壹些已經實現了的叠代器使用確實方便,但是如果需要自己去寫壹個叠代器呢?下面這段代碼就帶大家見識以下叠代器的實現。

在python中,能被next函數操作的對象壹定帶有__next__函數的實現,而能夠被叠代的對象有必須實現__iter__函數。看了這麽壹段操作,相信大家對叠代器實現的繁瑣也是深有體會了,那麽生成器的實現是不是會讓妳覺得更加簡單易用呢?不過千萬別產生壹個誤區,即生成器比叠代器簡單就多用生成器。 在實際開發中,如果遇到與大量磁盤文件或者數據庫操作相關的倒是可以使用生成器。但是在其他的任務中使用生成器難免有炫技,並且使邏輯不清晰而導致可讀性下降的嫌疑。 這大概也能解釋生成器受冷落的原因。不過作為壹個專業的開發者,熟悉語言特性是分內之事。

到此,關於生成器的討論就結束了。本文的notebook版本文件在github上的cnbluegeek/notebook倉庫中***享,歡迎感興趣的朋友前往下載。