生成器,生成器函數以及推導式,生成器表達式

一丶生成器

  生成器的本質就是迭代器

def func(): print("111") return 222 ret = func() print(ret) # 結果 111 222 #將函數中的return換成yield就成了生成器
def func(): print("111") yield 222 ret = func() print(ret) #結果 <generator object func at 0x0000019D9FF3D150>

 

  生成器的特色和迭代器同樣,取值方式和迭代器同樣(__next__(),send():給上一個yield的傳值)

def func(): print("111") yield 222 ret = func() ret1 = ret.__next__() print(ret1)     #111 222 

 

def generator(): print(123) content = yield 1
    print('=======',content) print(456) yield2 g = generator() ret = g.__next__() print('***',ret) ret = g.send('hello')   #send的效果和next同樣
print('***',ret) #send 獲取下一個值的效果和next基本一致 #只是在獲取下一個值的時候,給上一yield的位置傳遞一個數據 #使用send的注意事項
    # 第一次使用生成器的時候 是用next獲取下一個值
    # 最後一個yield不能接受外部的值

 

  生成器通常由生成器函數和生成器表達式來建立

  其實就是手寫的迭代器

二丶生成器函數

  和普通函數沒有區別,裏面有yield的函數就是生成器函數

  生成器函數在執行的時候默認不會執行函數體,返回生成器

  經過生成器__next__() 分段執行這個函數

# 例題: # 一公司訂購10000件衣服,而員工並無這麼多,一次分不完只能堆起來.佔空間
def cloth(): lst = [] for i in range(10000): lst.append("衣服"+ str(i)) return lst cl = cloth() #最好的方法是來一個新員工領一套,不用一次性作那麼多件衣服,用多少取多少.
def cloth(): lst = [] for i in range(10000): lst.append("衣服"+ str(i)) yield lst cl = cloth()

 

 區別: 第⼀種是直接⼀次性所有拿出來. 會很佔⽤內存. 第⼆種使⽤⽣成器. ⼀次就⼀個. ⽤多少⽣成多少. ⽣成器是⼀個⼀個的指向下⼀個.不會回去, __next__()到哪, 指針就指到哪⼉.下一次繼續獲取指針指向的值.

 

 send()給上一個yield傳值,不能在開頭(沒有上一個yield),最後一個yield也不能用send()

def eat(): print("我吃什麼啊") a = yield "饅頭"
    print("a=",a) b = yield "⼤餅"
    print("b=",b) c = yield "⾲菜盒⼦"
    print("c=",c) yield "GAME OVER" gen = eat() # 獲取⽣成器
ret1 = gen.__next__() print(ret1) ret2 = gen.send("胡辣湯") print(ret2) ret3 = gen.send("狗糧") print(ret3) ret4 = gen.send("貓糧") print(ret4)

 

三丶推導式

  1.列表推導式[結果   for循環   條件篩選]

lst = [] for i in range(1,15): lst.append(i) print(lst) #替換成列表推導式
lst = [i for i in range(1,15)] print(lst)

 

  2.字典推導式{K:V for循環  條件篩選}

# 把字典中的key和value互換
dic = {'a': 1, 'b': '2'} new_dic = {dic[key]: key for key in dic} print(new_dic) # 在如下list中. 從lst1中獲取的數據和lst2中相對應的位置的數據組成⼀個新字典
lst1 = ['jay', 'jj', 'sylar'] lst2 = ['周杰倫', '林俊杰', '邱彥濤'] dic = {lst1[i]: lst2[i] for i in range(len(lst1))} print(dic)

 

  3.集合推導式{K  for循環  條件}

#集合推導式能夠幫咱們去重
lst = [1,1,2,4,9,6,8,4,2,6] s = {i for i in lst} print(s)    #{1, 2, 4, 6, 8, 9}

 

四丶生成器表達式

  (結果 for循環 條件)

# 獲取1-100能被3整除的數
gen = (i for i in range(1,100) if i%3 ==0) for num in gen: print(num) # 100之內能被3整除的數的平⽅
gen = (i*i for i in range(1,100) if i%3 == 0) for num in gen: print(num) # 尋找名字中帶有兩個e的⼈的名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven','Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] # #不用推導式和表達式
lst = [] for i in names: for name in i: if name.count("e") >= 2: lst.append(name) print(lst) #推導式
gen = (name for i in names for name in i if name.count("e") >= 2) for name in gen: print(name)

 

 生成器的惰性機制:

  生成器只有在訪問的時候才取值. 說白了. 你找他要他纔給你值. 不找他 要. 他是不會執行的.

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同理

 

  面試題:

 

def add(a,b): return a + b def test(): for r_i in range(4):    #獲取的是 0,1,2,3
        print("a") yield r_i g = test() for n in [2,10]: g = (add(n,i) for i in g) print(list(g))

 

 

 特色:

    1.惰性機制

    2.只能向前

    3.節省內存(雞蛋理論)

  生成器表達式和列表推導式的區別:

  1.列表推導式比較耗內存,一次性加載.生成器表達式幾乎不佔內存,使用的時候才分配和使用內存

  2.獲得的值不同,列表推導式獲得的是一個列表,生成器表達式得到的是一個生成器

相關文章
相關標籤/搜索