Python中Generators教程的實(shí)現(xiàn)
要想創(chuàng)建一個iterator,必須實(shí)現(xiàn)一個有__iter__()和__next__()方法的類,類要能夠跟蹤內(nèi)部狀態(tài)并且在沒有元素返回的時(shí)候引發(fā)StopIteration異常.
這個過程很繁瑣而且違反直覺.Generator能夠解決這個問題.
python generator是一個簡單的創(chuàng)建iterator的途徑.前面講的那些繁瑣的步驟都可以被generator自動完成.
簡單來說,generator是一個能夠返回迭代器對象的函數(shù).
怎樣創(chuàng)建一個python generator?
就像創(chuàng)建一個函數(shù)一樣簡單,只不過不使用return 聲明,而是使用yield聲明.
如果一個函數(shù)至少包含一個yield聲明(當(dāng)然它也可以包含其他yield或return),那么它就是一個generator.
yield和return都會讓函數(shù)返回一些東西,區(qū)別在于,return聲明徹底結(jié)束一個函數(shù),而yield聲明是暫停函數(shù),保存它的所有狀態(tài),并且后續(xù)被調(diào)用后會繼續(xù)執(zhí)行.
generator函數(shù)和普通函數(shù)的區(qū)別
- generator函數(shù)包含一個以上的yield聲明
- generator函數(shù)被調(diào)用的時(shí)候,會返回一個iterator對象,但是函數(shù)并不會立即開始執(zhí)行
- __iter__()和__next__()方法被自動實(shí)現(xiàn),所以可以使用next()函數(shù)對返回的此iterator對象進(jìn)行迭代
- 一旦一個generator 執(zhí)行到y(tǒng)ield語句,generator函數(shù)暫停,程序控制流被轉(zhuǎn)移到調(diào)用方
- 在對generator的連續(xù)調(diào)用之間,generator的本地變量和狀態(tài)會被保存
- 最終,generator函數(shù)終止,再調(diào)用generator會引發(fā)StopIteration異常
下面這個例子說明上述全部要點(diǎn),我們有一個名為my_gen()的函數(shù),它帶有一些yield聲明.
# A simple generator function def my_gen(): n = 1 print('This is printed first') # Generator function contains yield statements yield n n += 1 print('This is printed second') yield n n += 1 print('This is printed at last') yield n
有趣的是,在這個例子里變量n在每次調(diào)用之間都被記住了。和一般函數(shù)不同的是,在函數(shù)yield之后本地變量沒有被銷毀,而且,generator對象只能被這樣迭代一次。
要想重復(fù)上面的過程,需要類似 a = my_gen() 這樣創(chuàng)建另一個generator對象,并對其使用next方法迭代。
注意
:我們可以對generator對象直接使用for循環(huán)。
這是因?yàn)橐粋€for循環(huán)接收一個iterator對象,且使用next()函數(shù)迭代它,當(dāng)遇到StopIteration異常的時(shí)候自動停止。
# A simple generator function def my_gen(): n = 1 print('This is printed first') # Generator function contains yield statements yield n n += 1 print('This is printed second') yield n n += 1 print('This is printed at last') yield n # Using for loop # Output: # This is printed first # 1 # This is printed second # 2 # This is printed at last # 3 for item in my_gen(): print(item)
有循環(huán)的python generator
上面的例子沒有實(shí)際的應(yīng)用意義,我們只是為了探究背后原理。
通常來說,generator都是和循環(huán)結(jié)合實(shí)現(xiàn)的,且這個循環(huán)帶有一個終止條件。
我們來看一個reverse一個字符串的例子
def rev_str(my_str): length = len(my_str) for i in range(length - 1,-1,-1): yield my_str[i] # For loop to reverse the string # Output: # o # l # l # e # h for char in rev_str("hello"): print(char)
我們在for循環(huán)里面使用range()函數(shù)來獲取反向順序的index。
generator除了可以應(yīng)用于string,還可以應(yīng)用于其它類型的iterator,例如list,tuple等。
python generator 表達(dá)式
使用generator表達(dá)式可以很容易地創(chuàng)建簡單的generator。
就像lambda函數(shù)可以創(chuàng)建匿名函數(shù)一樣,generator函數(shù)創(chuàng)建一個匿名generator函數(shù)。
generator表達(dá)式的語法類似于python的list comprehension,只是方括號被替換為了圓括號而已。
list comprehension和generator表達(dá)式的主要區(qū)別在于,前者產(chǎn)生全部的list,后者每次僅產(chǎn)生一項(xiàng)。
它們有些懶惰,僅在接到請求的時(shí)候才會產(chǎn)生輸出。因此,generator表達(dá)式比list comprehension更加節(jié)省內(nèi)存。
# Initialize the list my_list = [1, 3, 6, 10] # square each term using list comprehension # Output: [1, 9, 36, 100] [x**2 for x in my_list] # same thing can be done using generator expression # Output: <generator object <genexpr> at 0x0000000002EBDAF8> (x**2 for x in my_list)
上面的例子中,generator表達(dá)式?jīng)]有立即產(chǎn)生需要的結(jié)果,而是在需要產(chǎn)生item的時(shí)候返回一個generator對象。
# Intialize the list my_list = [1, 3, 6, 10] a = (x**2 for x in my_list) # Output: 1 print(next(a)) # Output: 9 print(next(a)) # Output: 36 print(next(a)) # Output: 100 print(next(a)) # Output: StopIteration next(a)
generator表達(dá)式可以在函數(shù)內(nèi)部使用。當(dāng)這樣使用的時(shí)候,圓括號可以丟棄。
python里為什么要使用generator?
1.容易實(shí)現(xiàn)
相對于iterator類來說,generator的實(shí)現(xiàn)清晰、簡潔。下面是用iterator實(shí)現(xiàn)一個2的指數(shù)函數(shù)
class PowTwo: def __init__(self, max = 0): self.max = max def __iter__(self): self.n = 0 return self def __next__(self): if self.n > self.max: raise StopIteration result = 2 ** self.n self.n += 1 return result
generator這樣實(shí)現(xiàn)
def PowTwoGen(max = 0): n = 0 while n < max: yield 2 ** n n += 1
因?yàn)間enerator自動跟蹤實(shí)現(xiàn)細(xì)節(jié),因此更加清晰、簡潔。
2.節(jié)省內(nèi)存
一個函數(shù)返回一個序列(sequence)的時(shí)候,會在內(nèi)存里面把這個序列構(gòu)建好再返回。如果這個序列包含很多數(shù)據(jù)的話,就過猶不及了。
而如果序列是以generator方式實(shí)現(xiàn)的,就是內(nèi)存友好的,因?yàn)樗看沃划a(chǎn)生一個item。
3.代表無限的stream
generator是一個很棒的表示無限數(shù)據(jù)流的工具。無限數(shù)據(jù)流不能被保存在內(nèi)存里面,并且因?yàn)間enerator每次產(chǎn)生一個item,它就可以表示無限數(shù)據(jù)流。
下面的代碼可以產(chǎn)生所有的奇數(shù)
def all_even(): n = 0 while True: yield n n += 2
4.generator流水線(pipeline)
generator可以對一系列操作執(zhí)行流水線操作。
假設(shè)我們有一個快餐連鎖店的日志。日志的第四列是每小時(shí)售出的披薩數(shù)量,我們想對近5年的這一數(shù)據(jù)進(jìn)行求和。
假設(shè)所有數(shù)據(jù)都是字符,不可用的數(shù)據(jù)都以"N/A"表示,使用generator可以這樣實(shí)現(xiàn)
with open('sells.log') as file: pizza_col = (line[3] for line in file) per_hour = (int(x) for x in pizza_col if x != 'N/A') print("Total pizzas sold = ",sum(per_hour))
這個流水線既高效又易讀,并且看起來很酷!:)
到此這篇關(guān)于Python中Generators教程的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Python Generators內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python使用functools實(shí)現(xiàn)注解同步方法
這篇文章主要介紹了Python使用functools實(shí)現(xiàn)注解同步方法,非常不錯,具有參考借鑒價(jià)值,需要的朋友可以參考下2018-02-02python使用正則表達(dá)式的search()函數(shù)實(shí)現(xiàn)指定位置搜索功能
SEARCH函數(shù),函數(shù)名。主要用來返回指定的字符串在原始字符串中首次出現(xiàn)的位置 ,從左到右查找,忽略英文字母的大小寫。接下來通過本文給大家介紹python使用正則表達(dá)式的search()函數(shù)實(shí)現(xiàn)指定位置搜索功能,需要的朋友一起看看吧2017-11-11numpy展平數(shù)組ndarray.flatten()詳解
這篇文章主要介紹了numpy展平數(shù)組ndarray.flatten()詳解,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06Python argparse 解析命令行參數(shù)模塊詳情
這篇文章主要介紹了Python argparse 解析命令行參數(shù)模塊詳情,argparse是python用于解析命令行參數(shù)和選項(xiàng)的標(biāo)準(zhǔn)模塊,用于代替已經(jīng)過時(shí)的optparse模塊2022-07-07python3圖片轉(zhuǎn)換二進(jìn)制存入mysql
MYSQL是支持把圖片存入數(shù)據(jù)庫的,也相應(yīng)的有一個專門的字段BLOB (Binary Large Object),即較大的二進(jìn)制對象字段,看下面代碼2013-12-12