成為Python大牛必須要掌握的高階語法——yield
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. 為什麼要使用yield
看了上述兩個迭代過程,大家可能有些疑問,使用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
可以看到,從第三項開始的每一項都是前兩項的和,這樣的輸出結果就是我們要的斐波那契數列。
相關文章
- git 必須要熟練掌握的命令Git
- JavaScript必須要掌握的知識-作用域JavaScript
- 如何使用CSS建立高階動畫,這個函式必須掌握CSS動畫函式
- shell程式設計必須要掌握的命令-xargs程式設計
- 學習web前端,必須要掌握的CSS原理Web前端CSS
- 為什麼學習web前端開發,必須要掌握好JavaScript這門程式語言?Web前端JavaScript
- 必須要懂的JS之(rest引數與spread語法)JSREST
- C語言必須掌握的判斷題 | 4C語言
- C語言必須掌握的判斷題 | 10C語言
- 成為java高階程式設計師需要掌握哪些Java程式設計師
- java開發必須要掌握的20個核心技術Java
- JavaScript必須要掌握的知識-作用域編寫提升JavaScript
- Java程式設計師面試必須要掌握的面試題Java程式設計師面試題
- 學好Spark/Kafka必須要掌握的Scala技術點(三)高階函式、方法、柯里化、隱式轉換SparkKafka函式
- 深入理解Python的yield from語法Python
- python高階語法:繼承性Python繼承
- 年薪50萬的Web前端大牛,必須經歷的3個階段!Web前端
- 程式設計師生存指南:你必須要掌握的兩點!程式設計師
- 大資料中必須要掌握的 Flink SQL 詳細剖析大資料SQL
- 網際網路時代,營銷人必須要掌握的能力
- C語言初學者必須掌握的關鍵字!C語言
- 轉:成為Java高階程式設計師需要掌握哪些?Java程式設計師
- Git中~你必須掌握的!Git
- Java Annotation 必須掌握的特性Java
- Linux新手入門必須要掌握的10個知識點!Linux
- 遊戲開發者必須掌握的移動廣告6大要點遊戲開發
- 成為Android高手必須掌握的28大項內容和10個建議Android
- Typescript 高階語法進階TypeScript
- 高階 Java 必須突破的 10 個知識點!Java
- 高階Java必須突破的10個知識點!Java
- JS高階之面試必須知道的幾個點JS面試
- C語言必須要記住的經典程式C語言
- CSS中那些必須掌握的概念CSS
- 前端必須掌握的知識點前端
- Java程式設計師微服務架構你必須要掌握的十個要點Java程式設計師微服務架構
- 成為優秀高階程式設計師的10個要點程式設計師
- aardio 開發桌面應用,這幾點必須要掌握!
- iOS 效能調優,成為一名合格 iOS 程式設計師必須掌握iOS程式設計師