Python中Generators教程的實現(xiàn)
要想創(chuàng)建一個iterator,必須實現(xiàn)一個有__iter__()和__next__()方法的類,類要能夠跟蹤內(nèi)部狀態(tài)并且在沒有元素返回的時候引發(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)用的時候,會返回一個iterator對象,但是函數(shù)并不會立即開始執(zhí)行
- __iter__()和__next__()方法被自動實現(xiàn),所以可以使用next()函數(shù)對返回的此iterator對象進行迭代
- 一旦一個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異常
下面這個例子說明上述全部要點,我們有一個名為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)。
這是因為一個for循環(huán)接收一個iterator對象,且使用next()函數(shù)迭代它,當(dāng)遇到StopIteration異常的時候自動停止。
# 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
上面的例子沒有實際的應(yīng)用意義,我們只是為了探究背后原理。
通常來說,generator都是和循環(huán)結(jié)合實現(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 表達式
使用generator表達式可以很容易地創(chuàng)建簡單的generator。
就像lambda函數(shù)可以創(chuàng)建匿名函數(shù)一樣,generator函數(shù)創(chuàng)建一個匿名generator函數(shù)。
generator表達式的語法類似于python的list comprehension,只是方括號被替換為了圓括號而已。
list comprehension和generator表達式的主要區(qū)別在于,前者產(chǎn)生全部的list,后者每次僅產(chǎn)生一項。
它們有些懶惰,僅在接到請求的時候才會產(chǎn)生輸出。因此,generator表達式比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表達式?jīng)]有立即產(chǎn)生需要的結(jié)果,而是在需要產(chǎn)生item的時候返回一個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表達式可以在函數(shù)內(nèi)部使用。當(dāng)這樣使用的時候,圓括號可以丟棄。
python里為什么要使用generator?
1.容易實現(xiàn)
相對于iterator類來說,generator的實現(xiàn)清晰、簡潔。下面是用iterator實現(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這樣實現(xiàn)
def PowTwoGen(max = 0):
n = 0
while n < max:
yield 2 ** n
n += 1
因為generator自動跟蹤實現(xiàn)細節(jié),因此更加清晰、簡潔。
2.節(jié)省內(nèi)存
一個函數(shù)返回一個序列(sequence)的時候,會在內(nèi)存里面把這個序列構(gòu)建好再返回。如果這個序列包含很多數(shù)據(jù)的話,就過猶不及了。
而如果序列是以generator方式實現(xiàn)的,就是內(nèi)存友好的,因為他每次只產(chǎn)生一個item。
3.代表無限的stream
generator是一個很棒的表示無限數(shù)據(jù)流的工具。無限數(shù)據(jù)流不能被保存在內(nèi)存里面,并且因為generator每次產(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ù)量,我們想對近5年的這一數(shù)據(jù)進行求和。
假設(shè)所有數(shù)據(jù)都是字符,不可用的數(shù)據(jù)都以"N/A"表示,使用generator可以這樣實現(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))
這個流水線既高效又易讀,并且看起來很酷?。海?/p>
到此這篇關(guān)于Python中Generators教程的實現(xiàn)的文章就介紹到這了,更多相關(guān)Python Generators內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python神經(jīng)網(wǎng)絡(luò)Inception?ResnetV2模型復(fù)現(xiàn)詳解
這篇文章主要為大家介紹了python神經(jīng)網(wǎng)絡(luò)Inception?ResnetV2模型復(fù)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05
pymongo如何通過oplog獲取數(shù)據(jù)(mongodb)
使用MongoDB的oplog(操作日志)進行數(shù)據(jù)同步是高級的用法,主要用于復(fù)制和故障恢復(fù),這篇文章主要介紹了pymongo通過oplog獲取數(shù)據(jù)(mongodb),需要的朋友可以參考下2023-09-09
python GUI庫圖形界面開發(fā)之PyQt5瀏覽器控件QWebEngineView詳細使用方法
這篇文章主要介紹了python GUI庫圖形界面開發(fā)之PyQt5瀏覽器控件QWebEngineView詳細使用方法,需要的朋友可以參考下2020-02-02
OpenCV之理解KNN鄰近算法k-Nearest?Neighbour
這篇文章主要為大家介紹了OpenCV之理解KNN鄰近算法k-Nearest?Neighbour,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-05-05

