python基础(part16)--生成器
鄙人學習筆記
開發(fā)工具:Spyder
文章目錄
- 生成器generator
- 生成器函數(shù)
- 舉個例子1(迭代器-->過渡-->生成器)
- 舉個例子2
- 內(nèi)置生成器
- 舉個例子1
- 舉個例子2
- 枚舉函數(shù)enumerate
- zip
- 生成器表達式
- 舉個例子1
- 舉個例子2
生成器generator
- 定義
能夠動態(tài)(循環(huán)一次計算一次返回一次)提供數(shù)據(jù)的可迭代對象。
- 作用
在循環(huán)過程中,按照某種算法推算數(shù)據(jù),不必創(chuàng)建容器,存儲完整的結(jié)果,從而節(jié)省內(nèi)存空間。數(shù)據(jù)量越大,優(yōu)勢越明顯。
備注:以上生成器的操作,也稱為惰性操作/延遲操作,通俗的講就是在需要的時候才計算結(jié)果,而不是一次構(gòu)建出所有結(jié)果。
生成器函數(shù)
- 定義
生成器函數(shù)是含有yield語句的函數(shù),生成器函數(shù)的返回值為生成器對象。只要我們的函數(shù)中有yield,那么這個函數(shù)就是生成器函數(shù)。
- 語法
創(chuàng)建生成器函數(shù):
def 生成器函數(shù)名():...yield 數(shù)據(jù)...調(diào)用生成器函數(shù):
my_iter = 生成器函數(shù)名()for 變量名 in my_iter:語句- 說明
①調(diào)用生成器函數(shù)將返回一個生成器對象my_iter時,不執(zhí)行生成器函數(shù)體。在for循環(huán)內(nèi),調(diào)用__next__()方法時,才執(zhí)行函數(shù)體。
②yield翻譯為”產(chǎn)生”或”生成”。
舉個例子1(迭代器–>過渡–>生成器)
我們看一下,下面幾行代碼:
- 運行說明
首先,當程序執(zhí)行第24行代碼,即調(diào)用生成器函數(shù)my_range()時,它不會去執(zhí)行my_range()函數(shù)體里的內(nèi)容,而是先返回給變量iter01一個生成器對象,之后程序會繼續(xù)向下執(zhí)行for循環(huán)語句:
當執(zhí)行第25行語句時,for循環(huán)內(nèi)部調(diào)用了__next__()方法,這時才開始執(zhí)行my_range()函數(shù)體里的內(nèi)容:
當執(zhí)行到y(tǒng)ield語句時,程序又返回了,程序?qū)ield右邊的start作為__next__()方法的返回值,給了變量item:
之后的程序運行內(nèi)容,不言而喻。就不一一贅述了,有機會可以自己在python里,斷點調(diào)試,觀察一下~
舉個例子2
我想在列表[1, 2, 5, 4, 6, 7, 9]中選出所有偶數(shù),并且通過生成器函數(shù)來實現(xiàn)。
創(chuàng)建生成器函數(shù):
def get_even(target):for item in target:if item % 2 == 0:yield item備用1:我們每次寫生成器函數(shù)時,都要思考yield要返回什么內(nèi)容.
備用2:我們什么時候使用生成器函數(shù)呢?在我們的方法/函數(shù)需要向外返回多個結(jié)果時,可以使用生成器函數(shù).
調(diào)用生成器函數(shù):
list01 = [1, 2, 5, 4, 6, 7, 9] iter01 = get_even(list01)for item in iter01:print(item)結(jié)果:
我們其實不用生成器函數(shù),也可以拿到這個結(jié)果,比如以下代碼。
創(chuàng)建函數(shù):
def get_even01(target):result = []for item in target:if item %2 == 0:result.append(item)return result調(diào)用函數(shù):
list01 = [1, 2, 5, 4, 6, 7, 9] iter01 = get_even01(list01)for item in iter01:print(item)結(jié)果:
這個結(jié)果,同上面利用生成器函數(shù),得到的結(jié)果一樣。
那么我們?yōu)樯兑蒙善骱瘮?shù)呢?他的優(yōu)勢是啥呢?
因為,如果調(diào)用get_even01()方法,則會執(zhí)行g(shù)et_even01()方法體,將所有結(jié)果存在內(nèi)存中。但是,如果調(diào)用生成器函數(shù)get_even(), 則不會執(zhí)行方法體,在內(nèi)存中不會存儲數(shù)據(jù)。我們用for循環(huán),循環(huán)一次,也就是__next__()一次,計算一次,返回一次。即,需要一次,做一次。這種生成器函數(shù)的操作就叫做:惰性操作/延遲操作。
所以,在數(shù)據(jù)量非常大的情況下,如果不用生成器函數(shù)進行操作,則,我們的內(nèi)存很快就會被占滿。
內(nèi)置生成器
我們先舉兩個例子。
舉個例子1
我們看一段代碼:
結(jié)果:
我們再寫一個自定義函數(shù)my_enumerate,具有和上述例子中,enumerate函數(shù)所演示出來的相同的功能:
for循環(huán)測試一下:
結(jié)果:
嗯!一毛一樣~
舉個例子2
我們再看一段代碼:
list01 = [0, 6, 7] list02 = ["小白", "小黃", "大白"]for item in zip(list01, list02):print(item)結(jié)果:
若我們在列表list02中再加一個元素,使兩個列表元素不相同:
結(jié)果:
我們再寫一個自定義函數(shù)my_zip,具有和上述例子中,zip函數(shù)所演示出來的相同的功能(不考慮兩個列表元素不相同的情況):
for循環(huán)測試一下:
list01 = [0, 6, 7] list02 = ["小白", "小黃", "大白"]for item in my_zip(list01, list02):print(item)結(jié)果:
注意:我們稱這種必須由__next__()驅(qū)動的函數(shù)(enumerate() / zip()),叫做內(nèi)置生成器。
枚舉函數(shù)enumerate
- 語法
- 作用
遍歷可迭代對象時,可以將索引與元素組合為一個元組。
zip
- 語法
- 作用
將多個可迭代對象中對應(yīng)的元素組合成一個個元組,生成的元組個數(shù)由元素數(shù)量最小的可迭代對象決定。
生成器表達式
- 定義
用推導(dǎo)式形式創(chuàng)建生成器對象。
- 語法
舉個例子1
如果我們有一個列表list01=[2,3,4,6], 如下圖所示:
我們想得到列表內(nèi)的每個元素的平方,該咋整呢?
方式1:
方式2(列表推導(dǎo)式):
我們print一下result得到結(jié)果:
備注1:方式1的代碼是列表推導(dǎo)式的傳統(tǒng)寫法。
備注2:對于推導(dǎo)式,我們還學習了字典推到式,集合推導(dǎo)式。但是沒有元組推導(dǎo)式,這是為什么捏?這是因為,列表、字典、集合都是可變對象,可以不斷增加元素。而元組是不可變的。
我們再寫一段代碼:
這個可不是”元組推導(dǎo)式”(壓根沒有元組推導(dǎo)式),這是生成器表達式。
這時,我們再print一下result:
得到一個生成器對象。生成器的本質(zhì)是一個惰性查找機制,要調(diào)用它,就要用__next__(), 也就是可以用for循環(huán):
得到結(jié)果:
我們可以寫一個與這個生成器表達式功能相同的生成器函數(shù):
for循環(huán):
得到結(jié)果:
嗯!與利用生成器表達式運行的結(jié)果相同。
這時候我們就想問:列表推導(dǎo)式和生成器表達式有啥區(qū)別?這個問題就相當于問:列表推導(dǎo)式的傳統(tǒng)寫法與生成器函數(shù)有啥不同?
答:區(qū)別就是列表推導(dǎo)式的傳統(tǒng)寫法會用一個列表result存儲所有結(jié)論,占用內(nèi)存。而生成器函數(shù)是惰性操作,被調(diào)用一次__next__(), 才會計算并返回一次。
舉個例子2
分別使用列表推導(dǎo)式和生成器表達式,獲取列表[2, 3, 4, 5, 6]中,大于3的數(shù)據(jù)。
代碼:
list01 = [2, 3, 4, 5, 6]result01 = [item for item in list01 if item > 3] result02 = (item for item in list01 if item > 3)for item in result01:print(item)print("---------")for item in result02:print(item)結(jié)果:
備注:別看列表推導(dǎo)式和生成器表達式的代碼極其相似,但是他們內(nèi)部卻大有不同,【result01 = [item for item in list01 if item > 3]】是執(zhí)行所有操作,保存所有結(jié)果;【result02 = (item for item in list01 if item > 3】是返回了一個生成器對象 。我們也可以通過斷點調(diào)試,去加深理解。
總結(jié)
以上是生活随笔為你收集整理的python基础(part16)--生成器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python基础(part15)--迭代
- 下一篇: CSOL近身武器双持狂花乱舞专业文字视频