python學習第11天----生成器、生成器函式、推導式、生成器表示式
1.生成器(generator)
生成器的本質就是迭代器
1)生產器的三種生成方法
①通過生成器函式
②通過生成器表示式建立生成器
③通過資料轉換
2.生成器函式
1)函式中包含了關鍵字yield,當前這個函式就不再是普通的函數了,而是一個生成器函式;此執行這個函式(即呼叫),只會獲取到生成器,而不是去執行這個函式
def func(): print("九尾妖狐") yield "阿狸" #retuen換成了yield,表示次函式是一個生成器函式 func() #不再是執行函式,而是通過func()來建立一個生成器 print(func()) 輸出:View Code<generator object func at 0x000001A3D0380AF0>
#生成器的本質是迭代器,所以可以以迭代器的方式使用生成器
def func(): print("九尾妖狐") yield "阿狸" #retuen換成了yield,表示次函式是一個生成器函式 g = func() #不再是執行函式,而是通過func()來建立一個生成器 print(g.__next__()) 輸出: 九尾妖狐 阿狸View Code
2)return是直接返回函式的結果,結束函式的呼叫;yield也是返回結果,但會繼續往下執行,可以讓函式分段執行
def func(): print("九尾妖狐") yield "阿狸" #retuen換成了yield,表示次函式是一個生成器函式 print("遠古巫靈") yield "澤拉斯" print("無雙劍姬") yield "菲奧娜" g = func() #不再是執行函式,而是通過func()來建立一個生成器 print(g.__next__()) print(g.__next__()) print(g.__next__()) 輸出: 九尾妖狐 阿狸 遠古巫靈 澤拉斯 無雙劍姬 菲奧娜View Code
#注:生成器函式中,最後一個yield後面的內容,會被執行到,但是會報錯(StopIteration),所以在最後一個yield之後,是不寫程式碼的(最後一個yield後,再進行__next__()會報錯)
3.send方法
1)__next__()方法和send()方法的共同點和區別
①共同點:__next__()可以讓生成器向下執行一次;send()也可以讓生成器向下執行一次
def func(): print("九尾妖狐") yield "阿狸" #retuen換成了yield,表示次函式是一個生成器函式 print("遠古巫靈") yield "澤拉斯" print("無雙劍姬") yield "菲奧娜" g = func() #不再是執行函式,而是通過func()來建立一個生成器 print(g.__next__()) print(g.send(1)) print(g.__next__()) 輸出: 九尾妖狐 阿狸 遠古巫靈 澤拉斯 無雙劍姬 菲奧娜View Code
②區別:send()該可以給上一個yield傳一個值;但是不能給最後一個yield傳送值,否則會報錯,在第一次執行生成器的時候,只能使用__next__(),不能使用send(), 因為此時沒有上一個yield
def func(): print("九尾妖狐") #黃色區域表示第一個__next__()的執行 a = yield "阿狸" #send傳入的值賦值給了a print(a) #a的值由send傳入 print("遠古巫靈") b = yield "澤拉斯" #藍色區域為send()的執行 print(b) print("無雙劍姬") c = yield "菲奧娜" #灰色區域為下一個send()執行 g = func() #不再是執行函式,而是通過func()來建立一個生成器 print(g.__next__()) print(g.send(666)) print(g.send(999)) 輸出: 九尾妖狐 阿狸 666 遠古巫靈 澤拉斯 999 無雙劍姬 菲奧娜View Code
例:將生成器轉換物件轉化為一個列表
def func(): yield 11 yield 12 yield 13 yield 44 g = func() lst = list(g) print(lst) 輸出: [11, 12, 13, 44]View Code
4.推倒式
1)引入:生成一個列表,裡面裝1-14的資料
lst = [] for i in range(1,15): lst.append("python%s" % i) print(lst) 輸出: ['python1', 'python2', 'python3', 'python4', 'python5', 'python6', 'python7', 'python8', 'python9', 'python10', 'python11', 'python12', 'python13', 'python14']View Code
2)列表推導式完成上述要求
①語法
[最終結果(變數) for 變數 in 可迭代物件]
②完成上述要求
lst = ["python%s" % i for i in range(1,15)] print(lst) 輸出: ['python1', 'python2', 'python3', 'python4', 'python5', 'python6', 'python7', 'python8', 'python9', 'python10', 'python11', 'python12', 'python13', 'python14']View Code
③純數字
lst = [ i for i in range(1,15)] print(lst) 輸出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]View Code
④練習:
#獲取1-100內能被3整數的數
lst = [i for i in range(1,101) if i%2 ==0 ] print(lst) 輸出: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100]View Code
#獲取100以內能被3整除的數的平方
lst = [i*i for i in range(1,101) if i%3==0] print(lst) 輸出: [9, 36, 81, 144, 225, 324, 441, 576, 729, 900, 1089, 1296, 1521, 1764, 2025, 2304, 2601, 2916, 3249, 3600, 3969, 4356, 4761, 5184, 5625, 6084, 6561, 7056, 7569, 8100, 8649, 9216, 9801]View Code
#尋找名字中帶有兩個e的名字
names = [['Tom', 'Billy', 'Jefferson' , 'Andrew' , 'Wesley' , 'Steven' , 'Joe'],['Alice', 'Jill' , 'Ana', 'Wendy', 'Jennifer', 'Sherry' , 'Eva']] lst = [name for first in names for name in first if name.count("e")==2] print(lst) 輸出: ['Jefferson', 'Wesley', 'Steven', 'Jennifer']View Code
總結:其他的東西正常寫,只是把最終的結果提到了前面
5.生成器表示式
1)生成器表示式和列表推導式的語法基本一昂,只是把[]換成了();這時候產生的就不再是一個列表,而是一個生成器
g = (i for i in range(1,10)) print(g) #g為生成器物件,就生成器表示式生成 print(g.__next__()) print(list(g) 輸出: <generator object <genexpr> at 0x00000168E5FA0D00> 1 [2, 3, 4, 5, 6, 7, 8, 9]View Code
#迴圈輸出整個生成器
g = (i for i in range(1,10)) for el in g: print(el) 1 。 。 9View Code
2)生成器表示式和列表推導式的區別
①列表推導式比較耗費額你存,一次性載入。生成器表示式幾乎不佔用記憶體,使用的時候才分配和使用記憶體
②得到的值不一樣,列表推導式得到的是一個列表,生成器表示式獲取的是一個生成器
3)生成器的惰性機制:生成器只有在訪問的時候才取值,即找它要才給你值,不找它要,就不會執行;
同樣一籃子雞蛋,列表推導式:直接拿到一籃子雞蛋;生成器表示式:拿到一個老母雞,需要急待就給你下蛋
def func(): print(111) yield 222 g = func() # ⽣成器g g1 = (i for i in g) # ⽣成器g1. 但是g1的資料來源於g g2 = (i for i in g1) # ⽣成器g2. 來源g1 print(list(g)) # 獲取g中的資料. 這時func()才會被執⾏. 列印111.獲取到222. g完畢. print(list(g1)) # 獲取g1中的資料. g1的資料來源是g. 但是g已經取完了. g1 也就沒有資料 print(list(g2)) #和g1同理 輸出: 111 [222] [] []View Code
6.字典推導式
#將字典中的key和value互換
dic = {'a':"張三",'b':"李四"} dic_new = {dic[key]:key for key in dic} print(dic_new) 輸出: {'張三': 'a', '李四': 'b'}View Code
#將lst1列表中的值作為key;lst2列表中的值作為value,生成一個字典
lst1 = ["LOL","CF","DNF","qqfeiche"] lst2 = ["英雄聯盟","穿越火線","地下城與勇士","QQ飛車"] dic = {lst1[i]:lst2[i] for i in range(len(lst1))} print(dic) 輸出: {'CF': '穿越火線', 'LOL': '英雄聯盟', 'qqfeiche': 'QQ飛車', 'DNF': '地下城與勇士'}View Code
7.集合推導式
集合推導式可以直接生成一個集合;集合的特點的是無序,不重複;所以集合推導式自帶去重功能
lst = ["九尾妖狐","遠古巫靈","九尾妖狐","懲戒之箭"] s = {i for i in lst} #集合推導式 print(s) 輸出: {'懲戒之箭', '遠古巫靈', '九尾妖狐'}View Code
總結:推導式有列表推導式、字典推導式、集合推導式,但是沒有元組推導式
生成器表示式:(結果 for 變數 in 可迭代物件 if 條件篩選)
生成器表示式可以直接獲取到生成器物件,生成器物件可以直接進行for許納湖按,生成器具有惰性機制
例:
def add(a, b): return a + b def test(): for r_i in range(4): yield r_i g = test() for n in [2, 10]: g = (add(n, i) for i in g) # g = (add(n, i) for i in add(n, i) for i in g) # g = (add(n, i) for i in add(n, i) for i in test()) # g = (add(n, i) for i in add(n, i) for i in [0,1,2,3]) # g = (add(10, i) for i in add(10, i) for i in [0,1,2,3]) # g = (add(10, i) for i [10,11,12,13]) print(list(g)) 輸出: [20, 21, 22, 23]View Code
8.練習
1)用推導式完成:過濾掉長度小於3的字串列表,並將剩下的轉化成大寫字母
lst = ["apple","bababa","dog","pig","orange"] lst_new = [el.upper() for el in lst if len(el) > 3 ] print(lst_new) 輸出: ['APPLE', 'BABABA', 'ORANGE']View Code
2)推導式完成:求(x,y)其中x是0-5之間的偶數,y是0-5之間的奇陣列成的元組列表
lst = [(x,y) for x in range(5) if x%2==0 for y in range(5) if y%2==1] print(lst) 輸出: [(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]View Code
3)推導式完成:求M中3,6,9組成的列表M=[[1,2,3],[4,5,6].[7,8,9]]
M=[[1,2,3],[4,5,6],[7,8,9]] lst = [i[2] for i in M] print(lst) 輸出: [3, 6, 9]View Code
#倒著推導
M = [3, 6, 9] lst = [[i-2,i-1,i] for i in M] print(lst) [[1, 2, 3], [4, 5, 6], [7, 8, 9]]View Code
4)推導式:求出50以內能被3整除的數的平方,並放入到一個列表中
lst = [i*i for i in range(50) if i%3==0] print(lst) 輸出: [0, 9, 36, 81, 144, 225, 324, 441, 576, 729, 900, 1089, 1296, 1521, 1764, 2025, 2304]View Code
5)推導式構建一個列表[0,2,4,6,8,10,12,14,16,18]
lst = [i for i in range(0,20,2)] print(lst) 輸出: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]View Code