python3:生成器yield深度解析
生成器這個章節尤其的重要,我們以後的協程的部分要用到這個知識點.
什麼是生成器函式呢?
定義為:
只要方法裡有 yield 這個關鍵字 代表不是普通的函式,就可以認為是生成器函式 .
怎麼就不普通了,咱們和普通的比較下 ,程式碼如下:
def gen_func():
yield 1
def func():
return 1
print(gen_func(),func())
#列印結果
#<generator object gen_func at 0x000000000220AE60> 1
我們可以發現 gen_func() 返回的是一個物件,並不是1.
func()返回的是1 .
有的小夥伴該說了,那我們怎麼去訪問生成器裡面的1 呢?
這個是個好問題,我們訪問物件裡的值一定要用到前面的知識,迭代器和迭代物件.
PS:看來知識都是關聯的,要想遇到什麼就學什麼,絕對沒有思路.
我也不做多解釋,用程式碼解釋來的直接 :
from collections import Iterable, Iterator def gen_func(): yield 1 def func(): return 1 print(gen_func(),func()) print(isinstance(gen_func(),Iterable)) #True print(isinstance(gen_func(),Iterator)) #True print(next(gen_func())) # 1
借用小嶽嶽的一句話“這麼神奇呀,生成器也是迭代器”
有了這個我們就可以放心用for 迴圈進行輸出. 這太方便了吧.
那有較真的小夥伴該說了,你這不是瞎胡搞嗎,本來直接return 個返回值
直接輸出就行了,你非得再繞一大圈 然後再輸入,你感覺有意思嗎?
好像他說的也沒有錯呀,but 有個場景,我需要return 兩次甚至更多,如何做呢
按照你的方法,要更多return 唄, 好我就讓你心服口服,看看程式碼吧
def func():`在這裡插入程式碼片`
return 1
return 2
print(func())
#列印結果: 1
return 2 並沒有返回,為什麼呢, 因為在return 1 的時候已經斷掉了,後邊的程式碼不會執行.
小夥伴們該說了,這樣是行不通,那有什麼辦法嗎 ? 當然離不開這節的主題,答案是生成器
請看下邊的程式碼:
def gen_func():
yield 1
yield 2
yield "Andy"
print(gen_func())
for i in gen_func():
print(i)
#列印結果
#<generator object gen_func at 0x000000000288F2B0>
#1
#2
#Andy
都打印出來了, 功能強爆了.
稍微解釋下:
當我們用for 迴圈的時候,會呼叫 第一個 next() 打印出1,然後在next()打印出2
一直迴圈到報 StopIteration 異常結束.
由於我們呼叫next()會返回一個值,不呼叫不會往下返回值,這個特性很重要,
官方的叫法是惰性求值 .
為了明白惰性求值的好處, 我來舉個例子 ,
經典斐波拉契
斐波那契數列指的是這樣一個數列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377
這個數列從第3項開始,每一項都等於前兩項之和。
用普通的方法,來 求10位之和
def func(index):
if index<=2:
return 1
else:
return func(index-1)+func(index-2)
print(func(10)) # 55
用普通的方法,也可用實現,但是我們有個問題就是 想列印它計算過程,你怎麼搞?
用普通的方法我們可以這麼寫:
def func2(index):
a=0
b=1
n=0
list_num=[]
while n<index:
list_num.append(b)
a,b=b,a+b
n+=1
return list_num
print(func2(10))
#列印結果 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
上邊的 a,b=b,a+b 就相當於 a=b , b=a+b 這也是迴圈的遞增方式.
有個問題,我們知道用list 有個缺點就是 效能低,如果index 很大的時候,不要用print,
這是血的教訓 ,我剛剛就重啟了. 還好部落格的內容還在. 當index 是上千萬的時候,也不要呼叫方法
,非常佔記憶體,你的機器同樣也會宕機。
我們開始用 生成器的方式進行訪問如下邊:
def gen_func(index):
a=0
b=1
n=0
while n<index:
a,b=b,a+b
n+=1
yield b
for i in gen_func(10):
print(i)
#列印結果
1
2
3
5
8
13
21
34
55
89
我們已經實現了列印過程,為什麼它可以使用index值為成千上萬的呢,這還是離不開生成器的惰性機制,
當呼叫 yield 的時候,會把數值存在生成器裡面,直到迴圈結束.
next()的時候,呼叫一下,不呼叫就不輸出.
更多的功能我會在一節介紹,請關注