1. 程式人生 > 實用技巧 >python學習第11天----生成器、生成器函式、推導式、生成器表示式

python學習第11天----生成器、生成器函式、推導式、生成器表示式

1.生成器(generator)

  生成器的本質就是迭代器

1)生產器的三種生成方法

①通過生成器函式

②通過生成器表示式建立生成器

③通過資料轉換

2.生成器函式

1)函式中包含了關鍵字yield,當前這個函式就不再是普通的函數了,而是一個生成器函式;此執行這個函式(即呼叫),只會獲取到生成器,而不是去執行這個函式

def func():
    print("九尾妖狐")
    yield "阿狸"      #retuen換成了yield,表示次函式是一個生成器函式
func()      #不再是執行函式,而是通過func()來建立一個生成器
print(func())
輸出:
<generator object func at 0x000001A3D0380AF0>
View Code

#生成器的本質是迭代器,所以可以以迭代器的方式使用生成器

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
。
。
9
View 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