動態規劃筆記
1.什麼是生成器:可以理解為一種資料型別,這種資料型別實現了迭代器協議(其他的資料型別需要呼叫自己內建的__iter__ 方法),所以生成器就是可迭代物件
2.生成器分類在python中的表現形式:(python有兩種不同的方式提供生成器)
(1)生成器函式:常規函式定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中,掛起函式的狀態,以使下次從他離開的地方繼續執行
def test(): print('開始生孩子了') yield '我' print('開始生兒子了') yield '兒子' yield'孫子' res = test() res呼叫了次函式,此時res就相當於一個生成器,支援__next__方法,同時也可以用for迴圈去遍歷它 即 for i in res:print(i) 會將所有內容列印(生孩子---孫子) print(res) print(res.__next__()) print(res.__next__()) 執行結果: <generator object test at 0x00000198BF0A30F8> 呼叫函式,相當於返回一個地址 (生成器) 需要通過res.__next__()來顯示開始生孩子了 我 開始生兒子了 兒子 從執行結果可以得知,yield返回了一個值,相當於return,其與return不同之處在於yield會儲存當前函式的執行狀態,所以第二次執行print(res.__next__())
是從print(‘開始生兒子了’)開始,並在yield ‘兒子’ 處停止並返回值
賣包子例項
def pro_baozi():for i in range(100): print('正在生產包子') yield '第 %s屜包子生產出來了' %i print('\n') print('第 %s屜包子賣出去了'%i) pro_g = pro_baozi() pro_g呼叫了函式,此時pro_g就可看作是一個生成器,此時它支援__next__方法 baozi1 =print(pro_g.__next__()) baozi1 =print(pro_g.__next__()) baozi1 =print(pro_g.__next__()) 執行結果: 正在生產包子 第 0屜包子生產出來了 函式執行到第一個 yield 暫停並返回值,第二次執行從當前位置開始直到再一次碰到 yield 暫停並返回值 此處開始到下一次換行前是第二次呼叫的結果,因為yield會保留函式的執行狀態,所以在第二次呼叫後,先執行print('\n'),因為print自帶換行,因此執行此語句換行了兩次 第 0屜包子賣出去了 正在生產包子 第 1屜包子生產出來了 第 1屜包子賣出去了 正在生產包子 第 2屜包子生產出來了
(2)生成器表示式:類似於列表推導,但是,生成器返回按需產生結果的一個物件,而不是一次構建一個結果列表
三元表示式
name = '焦國華' res = '帥哥' if name == '焦國華' else '沙雕' 這種形式就是三元表示式 print(res)
執行結果:
帥哥
列表解析
l = ['雞蛋%s' %i for i in range(10)] 這種形式就稱為列表解析,實際上也是[ ]內是一個二元表示式 也可以寫為 l = ['雞蛋%s' %i for i in range(10) if i >5] 執行輸出['雞蛋 0', '雞蛋 1', '雞蛋 2', '雞蛋 3', '雞蛋 4'] print(l) 執行結果:['雞蛋0', '雞蛋1', '雞蛋2', '雞蛋3', '雞蛋4', '雞蛋5', '雞蛋6', '雞蛋7', '雞蛋8', '雞蛋9']
總結:
(1)生成器表示式 把列表解析的 [ ] 換成()得到的就是生成器表示式
laomuji = ('雞蛋%s' %i for i in range(10)) print(laomuji) print(laomuji.__next__()) print(laomuji.__next__()) 執行結果: <generator object <genexpr> at 0x000001AFF8B8F048> 雞蛋0 雞蛋1
(2)列表解析與生成器表示式都是一種便利的程式設計方式,只不過生成器表示式更節省記憶體
(3)python不但使用迭代器協議,讓for迴圈變得更加通用。大部分內建函式,也是用迭代器協議訪問物件。例如,sum函式是python的內建函式,該函式使用迭代器協議訪問物件,而生成器實現了
迭代器協議,所以,我們可以直接這樣計算一系列值的和:
sum(x ** 2 for x in range(4)) 即內部可以直接寫一個生成器表示式,因為生成器表示式滿足迭代器協議
而不用多此一舉先構造一個列表
sum([x ** 2 for x in range(4)])
3.生成器總結:
(1)語法上和函式類似:生成器函式和常規函式幾乎是一樣的,他們都是使用def語句進行定義,差別在於,生成器使用 yield 語句返回一個值,而常規函式使用 return 語句返回一個值
(2)自動實現迭代器協議:對於生成器,python會自動實現迭代器協議,以便應用到迭代背景中(如for迴圈、sum()函式)。由於生成器自動實現了迭代器協議,所以,我們可以呼叫它的__next__
方法,並且,在沒有值可以返回的時候,生成器自動生成StopIteration異常
(3)狀態掛起:生成器使用yield語句返回一個值,yield語句掛起該生成器函式的狀態,保留足夠的資訊,以便之後從離開他的地方繼續執行
優點::生成器的好處之一