生成器的本質就是迭代器面試
生成器通常由生成器函數或者生成器表達式來建立app
其實就是手寫的迭代器函數
def func(): print("娃哈哈") yield 1 # return和yield均可以返回數據 print("呵呵呵") gen = func() # 獲取生成器,不會執行你的函數. 拿到的是一個生成器 print(gen)# >>> <generator object func at 0x0000021441B634F8> #不會拿到值,拿到的是個內存地址
和迭代器同樣.取值方式和迭代器同樣(__next__()spa
send(): 給上一個yield傳值).code
def func(): print("娃哈哈") yield 1 print("呵呵呵") gen = func() # 不會執行你的函數. 拿到的是生成器 print(gen.__next__()) #執行函數. 執行到下一個yield. >>> 結果: 娃哈哈 1
和普通函數沒有區別. 裏面有yield的函數就是生成器函數.blog
生成器函數在執行的時候. 默認不會執行函數體. 返回生成器內存
def func(): print("娃哈哈") yield 1 # return和yield均可以返回數據 print("呵呵呵") gen = func() # 不會執行你的函數. 拿到的是生成器 print(gen) >>> <generator object func at 0x00000181098B34F8>
yield: 至關於return 能夠返回數據. 可是yield不會完全中斷函數. 分段執行函數generator
''' 生成器有什麼好處呢?就是不會一會兒在內存中生成太多數據 假如我想讓工廠給學生作校服,生產2000000件衣服,我和工廠一說,工廠應該是先答應下來,而後再去生產,我能夠一件一件的要,也能夠根據學生一批一批的找工廠拿。 而不能是一說要生產2000000件衣服,工廠就先去作生產2000000件衣服,等回來作好了,學生都畢業了。。。 ''' def order(): lst = [] for i in range(200000): lst.append("衣服"+str(i)) return lst g = order() print(g) # 這個數據太龐大了,一下處理2000000件衣服... #咱們加了yield就不同了,咱們能夠根據本身的需求要衣服 def order(): """生產衣服""" for i in range(2000000): yield "生產了第%s件衣服"%i g =order() print(g.__next__()) #要一件衣服 print(g.__next__()) #再要一件衣服 print(g.__next__()) #再要一件衣服 num = 0 for i in g: #要一批衣服,好比5件 print(i) num +=1 if num == 5: break
經過生成器的__next__()分段執行這個函數.it
send() 給上一個yield傳值, 不能再開頭(沒有上一個yield), 最後一個yield也不能夠用send()for循環
#send() 和__next__()是同樣的. 能夠執行到下一個yield, 能夠給上一個yield位置傳值 def func(): print("我是第一個段") a = yield 123 print(a) print("周杰倫是第二段") b = yield 456 print(b) # ?? print("林俊杰是第三段") c = yield 789 print(c) print("王力宏是最後一個段") yield 79 # 最後收尾必定是yield g = func() print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__()) >>> 我是第一個段 123 None 周杰倫是第二段 456 None 林俊杰是第三段 789 None 王力宏是最後一個段 79 g = func() #獲取生成器 print(g.__next__()) # 沒有上一個yield 因此不能使用send() 開頭必須是__next__() print(g.send("煎餅果子")) #向第一個yield傳值 print(g.send("韭菜盒子")) #向上一個yield傳值 print(g.send("鍋包肉")) #向上一個yield傳值 >>> 我是第一個段 123 煎餅果子 周杰倫是第二段 456 韭菜盒子 林俊杰是第三段 789 鍋包肉 王力宏是最後一個段 79
用一句話來生成一個列表
[結果 for循環 條件篩選]
#50之內的奇數 lst = [i for i in range(50) if i%2==1] print(lst) >>> [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49]
字典推導式 {k:v for循環 條件篩選}
#key和value顛倒 dic = {"jj": "林俊杰", "jay": "周杰倫", "zs": "趙四", "ln":"劉能"} d = {v : k for k,v in dic.items()} print(d) >>> {'林俊杰': 'jj', '周杰倫': 'jay', '趙四': 'zs', '劉能': 'ln'}
{k for循環 條件}
#集合有去重做用 lst = [1, 1, 4, 6,7,4,2,2] s = { el for el in lst } print(s) >>> {1, 2, 4, 6, 7}
元組tuple沒有推導式,生產器表達式
(結果 for循環 條件)
tu = (i for i in range(10)) # 沒有元組推導式. 生成器表達式 print(tu) # 生成器 >>> <generator object <genexpr> at 0x00000136D23B34F8> #既然是生成器那咱們就能夠用 __next__來拿值 print(tu.__next__()) print(tu.__next__()) print(tu.__next__()) print(tu.__next__()) print(tu.__next__()) print(tu.__next__()) print(tu.__next__()) >>> 0 1 2 3 4 5 6
惰性機制
只能向前
節省內存
#值2000塊的面試題!!! def func(): print(111) yield 222 yield 333 g = func() # 獲取生成器 g1 = (i for i in g) # 生成器 g2 = (i for i in g1) # 生成器 print(list(g)) # 111 [222,333] 源頭. 從源頭把數據拿走了 # print(list(g1)) # [] 都是要從源頭拿數據的,因此這裏執行的時候. 源頭已經被g取走了,沒有了數據 # print(list(g2)) # [] 這裏也沒有值了
#求和 def add(a, b): return a + b # 生成器函數 # 0-3 def test(): for r_i in range(4): yield r_i
升級版!!!
#0,1,2,3 g = test() # 獲取生成器 for n in [2, 10]: g = (add(n, i) for i in g) # 當n = 2時 g不取值,因沒有值,只是單純遍歷一下並無執 #行,這時候 g = (add(n,),for i in g) # 當n = 10時 g = (add(n+i),for i in add(n+i),for i in g) # 因惰性機制,運行到最後 g開始取值,從源頭取值,源頭g = 0,1,2,3 print(list(g)) # 代數,n =10時 g =(add(10+i),for i in add(10+0,1,2,3)) # i = 10,11,12,13 # 20,21,22,23 #list(g) 一次性全拿出來,因此 list(g) 結果 20,21,22,23