生成器的產(chǎn)生
?????對(duì)于for龙屉,range钻哩,Python內(nèi)部已經(jīng)把它封裝成了一個(gè)迭代器相速,那么如果我們想自定義一個(gè)迭代器的話碟渺,應(yīng)該怎么辦鲜锚?這時(shí)候就應(yīng)運(yùn)而生了生成器突诬。一個(gè)生成器必定是一個(gè)迭代器
創(chuàng)建生成器的兩種方式
1.生成器函數(shù)
def generator():
print("1")
yield "first"
print("2")
yield "second"
print("3")
yield "third"
if __name__ == '__main__':
g = generator()
print(g.__next__())
print(g.__next__())
print(g.__next__())
?????首先定義一個(gè)生成器函數(shù)需要yield關(guān)鍵字,它的作用和return很相似芜繁,但是return是結(jié)束這個(gè)函數(shù)旺隙,yield只表示此次next取值結(jié)束。
以上函數(shù)執(zhí)行流程為:
1.調(diào)用generator()函數(shù)骏令,返回一個(gè)生成器蔬捷。
2.調(diào)用第一個(gè)__next__(),這時(shí)進(jìn)入到generator()函數(shù)中榔袋,打印1周拐,并遇見第一個(gè)yield并返回”first“。
3.調(diào)用第二個(gè)__next__()凰兑,這時(shí)進(jìn)入到generator()函數(shù)中上次執(zhí)行到的yield的地方妥粟,打印2,并遇見第二個(gè)yield并返回”second“吏够。
4.第三次同理勾给。
5.如果在繼續(xù)調(diào)用__next__(),將會(huì)拋出StopIteration锅知。
yield from
def generator():
ls = [1,2,3,4]
yield from ls
?????yield from后跟一個(gè)可迭代對(duì)象播急,等價(jià)與依次yield這個(gè)可迭代對(duì)象中的每一個(gè)值。
2.生成器表達(dá)式
if __name__ == '__main__':
g = (i for i in range(10))
print(type(g))
?????將列表推導(dǎo)式的方括號(hào)改為圓括號(hào)就是一個(gè)生成器表達(dá)式
Tips:
- 生成器的本質(zhì)就是一個(gè)迭代器售睹,擁有__iter__()和__next__()方法桩警,只不過這個(gè)迭代器由開發(fā)人員自定義完成。
- 調(diào)用生成器函數(shù)(含有yield關(guān)鍵字的函數(shù))時(shí)昌妹,它并不執(zhí)行只返回一個(gè)生成器捶枢,每次調(diào)用next方法會(huì)取到一個(gè)值,直到取到最后一個(gè)值捺宗,之后再執(zhí)行next會(huì)報(bào)錯(cuò)柱蟀,即生成器的惰性計(jì)算。
獲取生成器中的值
1.next()方法
?????next()方法是Python中內(nèi)置的方法蚜厉,作用效果和__next__()一樣长已。next()方法的實(shí)現(xiàn)就是基于__next__()。由于是內(nèi)置方法所以next(g)
這樣使用。
2.send()方法
????? send()方法和next()方法有一樣的作用术瓮,都可以獲得下一個(gè)值康聂,但是send()在獲取下一個(gè)值的時(shí)候會(huì)給上一個(gè)yield傳一個(gè)值,故send()不能用在第一個(gè)胞四。
?????下面是一個(gè)動(dòng)態(tài)求平均值恬汁,利用裝飾器和生成器來實(shí)現(xiàn)
"""
裝飾器用來消耗第一次yield,觸發(fā)send()
"""
def init(func):
def inner(*args,**kwargs):
g = func(*args,**kwargs)
next(g)
return g
return inner
@init
def dynamiccal():
sum = 0
count = 0
avg = 0
while True:
num = yield avg
sum = sum + num
count = count + 1
avg = sum/count
if __name__ == '__main__':
g = dynamiccal()
for i in range(1,11):
print(g.send(i),end=' ')
3.for
?????生成器一定是迭代器辜伟,所以一定可以被for循環(huán)取值氓侧。
g = generator()
for i in g:
print(g)
4.強(qiáng)制轉(zhuǎn)換為列表
g = generator()
list(g)
?????將在每次yield返回的值放在列表中,但是這并不是一個(gè)好方法导狡,這樣就失去了生成器的靈魂约巷。