一個包含yield關鍵字的函數就是一個生成器函數。yield能夠爲咱們從函數中返回值,可是yield又不一樣於return,return的執行意味着程序的結束,調用生成器函數不會獲得返回的具體的值,而是獲得一個可迭代的對象。每一次獲取這個可迭代對象的值,就能推進函數的執行,獲取新的返回值。直到函數執行結束。編程
import time def genrator_fun1(): a = 1 print('如今定義了a變量') yield a b = 2 print('如今又定義了b變量') yield b g1 = genrator_fun1() print('g1 : ',g1) #打印g1能夠發現g1就是一個生成器 print('-'*20) #我是華麗的分割線 print(next(g1)) time.sleep(1) #sleep一秒看清執行過程 print(next(g1)) 初識生成器函數
從這能夠說明生成器能夠節省內存函數
#初識生成器二 def produce(): """生產衣服""" for i in range(2000000): yield "生產了第%s件衣服"%i product_g = produce() print(product_g.__next__()) #要一件衣服 print(product_g.__next__()) #再要一件衣服 print(product_g.__next__()) #再要一件衣服 num = 0 for i in product_g: #要一批衣服,好比5件 print(i) num +=1 if num == 5: break #到這裏咱們找工廠拿了8件衣服,我一共讓個人生產函數(也就是produce生成器函數)生產2000000件衣服。 #剩下的還有不少衣服,咱們能夠一直拿,也能夠放着等想拿的時候再拿 初識生成器二
import time def tail(filename): f = open(filename) f.seek(0, 2) #從文件末尾算起 while True: line = f.readline() # 讀取文件中新的文本行 if not line: time.sleep(0.1) continue yield line tail_g = tail('tmp') for line in tail_g: print(line) 生成器監聽文件輸入的例子
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不能接受外部的值
def averager(): total = 0.0 count = 0 average = None while True: term = yield average total += term count += 1 average = total/count g_avg = averager() next(g_avg) print(g_avg.send(10)) print(g_avg.send(30)) print(g_avg.send(5)) 計算移動平均值(1)
def init(func): #在調用被裝飾生成器函數的時候首先用next激活生成器 def inner(*args,**kwargs): g = func(*args,**kwargs) next(g) return g return inner @init def averager(): total = 0.0 count = 0 average = None while True: term = yield average total += term count += 1 average = total/count g_avg = averager() # next(g_avg) 在裝飾器中執行了next方法 print(g_avg.send(10)) print(g_avg.send(30)) print(g_avg.send(5)) 計算移動平均值(2)_預激協程的裝飾器
def gen1(): for c in 'AB': yield c for i in range(3): yield i print(list(gen1())) def gen2(): yield from 'AB' yield from range(3) print(list(gen2())) yield from
總結:spa
1.把列表解析的[]換成()獲得的就是生成器表達式code
2.列表解析與生成器表達式都是一種便利的編程方式,只不過生成器表達式更節省內存協程
3.Python不但使用迭代器協議,讓for循環變得更加通用。大部份內置函數,也是使用迭代器協議訪問對象的。例如, sum函數是Python的內置函數,該函數使用迭代器協議訪問對象,而生成器實現了迭代器協議,因此,咱們能夠直接這樣計算一系列值的和:對象
sum(x ** 2 for x in range(4))
而不用這樣例子:blog
sum([x ** 2 for x in range(4)])
例一:30之內全部與能被3整除的數ip
multiples = [i for i in range(30) if i % 3 is 0] print(multiples) # Output: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
例二:30之內全部能被3整除的數的平方內存
def squared(x): return x*x multiples = [squared(i) for i in range(30) if i % 3 is 0] print(multiples)
例三:找到嵌套列表中名字含有兩個‘e’的全部名字get
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] print([name for lst in names for name in lst if name.count('e') >= 2]) # 注意遍歷順序,這是實現的關鍵
例一:將一個字典的key和value對調
mcase = {'a': 10, 'b': 34} mcase_frequency = {mcase[k]: k for k in mcase} print(mcase_frequency)
例二:合併大小寫對應的value值,將k統一成小寫
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3} mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()} print(mcase_frequency)
squared = {x**2 for x in [1, -1, 2]} print(squared) # Output: set([1, 4])