DAY12 生成器初始与列表生成式
初識生成器
通過前面學習的迭代器,我們知道,迭代器十分節省內存。如果在某些情況下,我們也需要節省內存,就只能自己寫,我們自己用python代碼實現的迭代器就稱為生成器。
生成器:生成器就是自己用python代碼寫的迭代器,生成器的本質就是迭代器。
(1)因為本質是迭代器,所以自帶了__iter__方法和__next__方法。
(2)特點:惰性運算,開發者自定義。
python中提供的兩種方法構建生成器:
(1)生成器函數:與普通函數的return不同,而是使用yield關鍵字。yield語句一次返回一個結果,在每個結果中間掛起函數,以便下次從它離開的地方再次運行。
(2)生成式推導式:類似于列表推導式,但是不是一次性構建一個列表,而是按需每次返回一個值。
?
構建生成器方式一:生成器函數
一個包含yield關鍵字的函數就稱為生成器函數。與普通函數的return不同,函數一遇到return就會結束函數并給函數的執行者返回值;但是yield不會結束函數,而是返回值給'生成器對象.__next__()',每次獲得可迭代對象,就會推動函數的進行。
#一。回顧普通函數與return def func1(x):x +=1return x #函數遇到return關鍵字,就會結束函數并返回值給函數的執行者。res = func1(6) #函數的執行命令,并且接受函數的返回值 print(res)#二。生成器函數,yield關鍵字。 def gen1(x):x +=1print(1111)yield x #帶有yield關鍵字的函數,稱為生成器函數。print(2222)yield xgen_obj = gen1(5) #此時這個就不是函數的執行者了,是生成器的對象 print(gen_obj) >>><generator object gen1 at 0x000001DFD052FE08> print(gen_obj.__next__()) >>> #一個yield關鍵字,會把值返回個一個next,并且把函數掛起。 1111 6 print(gen_obj.__next__()) #第二個生成器對象,會從掛起處繼續向下執行,遇到第二個yield返回。 >>> 2222 6 print(gen_obj.__next__()) #生成器本質就是迭代器,只能一路走到黑,不能回頭,所以報錯。 >>> StopIteration#生成器范例二: def func1(x):x +=1yield xx +=3yield xx +=5yield x g1 = func1(5) #g1為生成器對象 print(g1.__next__()) #一個yield對應一個next,yield把值返回,所以x為6 print(g1.__next__()) #一個yield對應一個next,yield把值返回,所以6+3=9 print(g1.__next__()) #一個yield對應一個next,yield把值返回,所以9+5=14'''因為生成器本質就是迭代器,所以符合迭代協議''' for i in g1:print(i) >>> 6 9 14總結1:yield與return的區別?
答:return結束函數,給函數的執行者返回值。yield不會結束函數,一個next調用對應一個yield,yield把值返回給"生成器對象.__next__()"
總結2:生成器與迭代器的差別?
答:從內存級別來看,迭代器需要可迭代對象來進行轉化,可迭代對象非常占內存;生成器直接創建,不需要轉換,從本質上就節省內存。
send與next
send : send與next在取值上是一樣的,執行一個yield方法。但是send可以給上一個yield傳遞值。
謹記:(1)第一次取值永遠都是next。
(2)最后一個yield永遠也得不到send傳的值。
#一。send與next在取值上是一樣的,都是對應一個yield關鍵字。 def func1():print(1)yield 6print(2)yield 7print(3)yield 8g1 = func1() print(next(g1)) print(g1.send('alex')) print(next(g1)) >>> 1 6 2 7 3 8#二。但是send可以給上一個yield傳遞值 def func1():count = yield 6print(count)yield 7yield 8g1 = func1() print(next(g1)) #遇到next調用一個yield,此時yield返回值為6,所以next(g1)為6,yield無實體值,所以count為None g1.send('alex') #遇到send取值與next一致,對一個yield,但是會給上一個yield賦值,所以 count=‘alex print(next(g1)) #同上。 >>> 6 alex 8?
構建生成器方式二:生成器推導式
? 前提知識:列表生成式/列表推導式
1.一行代碼幾乎搞掂需求簡單的任何列表,方便。
2.不易排錯,不建議超過三次循環。
#一。循環模式 [ 變量 for 變量 in iterable ] list = [x for x in range(101)] print(list) >>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]l2 = [i**2 for i in range(1,11)] print(l2) >>> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]#二。篩選模式 [ 加工后的變量 for 變量 in Iterable if 條件] '''30以內被3整除的數''' print([ i for i in range(1,30) if i%3==0]) >>> [3, 6, 9, 12, 15, 18, 21, 24, 27]'''30以內被3整除的數的平方''' print([ i**2 for i in range(1,30) if i%3==0]) >>> [9, 36, 81, 144, 225, 324, 441, 576, 729]'''找出嵌套列表中名字含有兩個'e'的所有名字''' names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]print([j for i in names for j in i if j.count('e') >= 2]) >>> ['Jefferson', 'Wesley', 'Steven', 'Jennifer']生成器推導式
1.十分簡單,只需要把列表推導式[]換成()即可
# 通過生成式推導式構建生成器generatorg1 = (i for i in range(1,10000)) print(g1) print(g1.__next__()) print(g1.__next__()) print(g1.__next__()) print(g1.__next__()) >>> <generator object <genexpr> at 0x00000253C09DFE08> 1 2 3 4
?
?
轉載于:https://www.cnblogs.com/hebbhao/p/9505701.html
總結
以上是生活随笔為你收集整理的DAY12 生成器初始与列表生成式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ2252(BFS水题)
- 下一篇: 国家集训队 小Z的袜子