Python中的yield全方位解讀
Python中的yield
關于 yield 看了忘,忘了看,零零散散的總是理解不透徹。今天徹底記錄下,帶大家一探 yield 到底是什么?
關于生成器概念的解釋,摘自菜鳥教程解釋:
在 Python 中,使用了 yield 的函數(shù)被稱為生成器(generator)。 跟普通函數(shù)不同的是,生成器是一個返回迭代器的函數(shù),只能用于迭代操作,更簡單點理解生成器就是一個迭代器。 在調(diào)用生成器運行的過程中,每次遇到 yield 時函數(shù)會暫停并保存當前所有的運行信息,返回 yield 的值, 并在下一次執(zhí)行 next() 方法時從當前位置繼續(xù)運行。 調(diào)用一個生成器函數(shù),返回的是一個迭代器對象。
網(wǎng)上例子很多,所有例子一開始就是這樣的代碼:
# ?。?!這種代碼 建議別看,因為以我親身經(jīng)歷,初次理解生成器,看這樣的代碼根本看不懂的~ def evenNumber(max): n = 0 while n < max: yield n n += 2 for i in evenNumber(10): print(i)
一會兒我把上述代碼重新寫下。
在此之前,大家還是需要掌握什么是generator(生成器)。
generator(生成器)
最簡單的創(chuàng)建一個生成器的方式,只要把一個列表生成式的 [] 改成 () ,就創(chuàng)建了一個generator:
List = [i*2 for i in range(10)] print(List) #[0, 2, 4, 6, 8, 10, 12, 14, 16, 18] g = (x*2 for x in range(10)) print(g) #<generator object <genexpr> at 0x000001CBA42F3C10>
生成器(generator)能夠迭代的關鍵是它有一個next()方法,工作原理就是通過重復調(diào)用next()方法,直到捕獲一個異常。試一下:
g = (x*2 for x in range(10)) print(g.__next__()) # 0 print(g.__next__()) # 2 print(g.__next__()) # 4 #... ...
第二種方法就是, 如果一個函數(shù)中包含 yield 關鍵字,那么這個函數(shù)就不再是一個普通函數(shù),而是一個generator。調(diào)用函數(shù)就是創(chuàng)建了一個生成器(generator)對象。
著重講一下第二種方法,先看代碼,為了便于理解,我不寫循環(huán),寫一個生成器函數(shù):
def gen_example(): print ('第1次執(zhí)行啦~,還沒到第一個yield!') yield '我是第1個遇見的yield,你遇到我就要返回' print ('第2次執(zhí)行啦~,還沒到第二個yield') yield '我是第2個遇見的yield,你遇到我就要返回' print ('第3次執(zhí)行啦,我運行完 函數(shù)就執(zhí)行完畢啦~') for i in gen_example(): print(i) print("--------分割線--------")
執(zhí)行結果:
第1次執(zhí)行啦~,還沒到第一個yield!
我是第1個遇見的yield,你遇到我就要返回
--------分割線--------
第2次執(zhí)行啦~,還沒到第二個yield
我是第2個遇見的yield,你遇到我就要返回
--------分割線--------
第3次執(zhí)行啦,我運行完 函數(shù)就執(zhí)行完畢啦~
過程詳解:
第一次for 循環(huán)執(zhí)行到y(tǒng)ield結束 ,只執(zhí)行了這兩句代碼:
第二次循環(huán) 是從上一次的yield結束地方開始執(zhí)行, 到下一個yield結束(一定要多讀幾遍理解哦):
第三次循環(huán)是,從第二次遇見的yield結束地方開始執(zhí)行,一直到下一個yield結束(沒有yield,自動執(zhí)行結束)
通過上述規(guī)律我們不難發(fā)現(xiàn),yield相當于 return 返回一個值,并且記住這個返回的位置,下次迭代時,代碼從yield的下一條語句開始執(zhí)行!
為了驗證這個規(guī)律 我把本文開頭的代碼 重新寫下,用更容易懂的方式:
def evenNumber(max): n = 0 while n < max: yield n print("第二次是從這里開始的") n += 2 print(f"n在第二次是{n}") for i in evenNumber(2): print(i) print("--------分割線--------")
執(zhí)行結果:
0
--------分割線--------
第二次是從這里開始的
n在第二次是2
輸出:0, 是怎么得到的呢?函數(shù)第一次執(zhí)行,遇到y(tǒng)ield 就返回,所以此時就打印0。
第二次是從這里開始的,n在第二次是2 這又是怎么得到的呢?執(zhí)行yield后面的這部分,然后又進入循環(huán),while循環(huán)條件都不滿足,執(zhí)行結束。
實際第二次沒有返回值。如果你細心點就會發(fā)現(xiàn),第二次輸出都沒有分割線的內(nèi)容:
既然 第二次打印都終止了,為什么沒報錯? 好問題!因為調(diào)用next()來執(zhí)行生成器則會報錯,如果使用for循環(huán)遍歷,for循環(huán)會自動捕獲該異常,直接停止遍歷。
def evenNumber(max): n = 0 while n < max: yield n print("第二次是從這里開始的") n += 2 print(f"n在第二次是{n}") g = evenNumber(2) print(g.__next__()) print(g.__next__())
執(zhí)行結果,調(diào)用next方法就會報錯:
0
第二次是從這里開始的
n在第二次是2
Traceback (most recent call last):
File "test.py", line 17, in <module>
print(g.__next__())
StopIteration
***Repl Closed***
所以,就印證了我們的結論~! 現(xiàn)在來看一些簡單的生成器函數(shù)的例子,是不是就一下懂了。
如果看到這里還是沒懂 ,留言吧,我會好好反思我自;
留個小作業(yè) 大家可以試試分析下斐波那契數(shù)列的過程。
def fab(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 for n in fab(5): print n
其它補充
如何判斷是不是 生成器函數(shù)?
使用 isgeneratorfunction 判斷函數(shù)是否是 generator 函數(shù)
from inspect import isgeneratorfunction print(isgeneratorfunction(fab) ) #True
為什么生成器函數(shù)中的return 不能返回值?
先看代碼:
def evenNumber(max): n = 0 while n < max: yield n print("第二次是從這里開始的") n += 2 print(f"n在第二次是{n}") return 10 for i in evenNumber(10): print(i) print("--------分割線--------")
執(zhí)行結果:
0
--------分割線--------
第二次是從這里開始的
n在第二次是2
***Repl Closed***
為什么 我的return 的值 沒有在最后一次打印出來呢? 在官方文檔中是這樣解釋的:
python生成器函數(shù)中return 的作用就是終止生成器。
表示生成器運行完成了,可以結束了。然后生成器會拋出一個StopIteration的異常。
而for循環(huán)能夠檢測到這個異常,于是結束循環(huán),也不報錯。但是__next__()就會報錯哦~
到此這篇關于Python中的yield全方位解讀的文章就介紹到這了,更多相關Python中的yield內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
typing.Dict和Dict的區(qū)別及它們在Python中的用途小結
當在 Python 函數(shù)中聲明一個 dictionary 作為參數(shù)時,我們一般會把 key 和 value 的數(shù)據(jù)類型聲明為全局變量,而不是局部變量。,這篇文章主要介紹了typing.Dict和Dict的區(qū)別及它們在Python中的用途小結,需要的朋友可以參考下2023-06-06三分鐘教會你用Python+OpenCV批量裁剪xml格式標注的圖片
最近學習網(wǎng)絡在線課程的過程中,為了方便課后復習,使用手機截取了大量的圖片,下面這篇文章主要給大家介紹了如何通過三分鐘教會你用Python+OpenCV批量裁剪xml格式標注圖片的相關資料,需要的朋友可以參考下2022-01-01PyCharm Python Console中文輸出亂碼問題及解決
這篇文章主要介紹了PyCharm Python Console中文輸出亂碼問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07Pandas實現(xiàn)數(shù)據(jù)類型轉換的一些小技巧匯總
這篇文章主要給大家匯總介紹了關于Pandas實現(xiàn)數(shù)據(jù)類型轉換的一些小技巧,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-05-05