1、生成器函數
一、生成器:就是本身用python代碼寫的迭代器,生成器的本質就是迭代器(因此自帶了__iter__方法和__next__方法,不須要咱們去實現)。
二、用如下兩種方式構建一個生成器:
1,生成器函數:跟常規函數定義相似,可是,使用yield語句而不是return語句返回結果。
yield語句一次返回一個結果,在每一個結果中間,掛起函數的狀態,以便下次從它離開的地方繼續執行。python
2,生成器表達式:相似於列表推導,可是,返回的是生成器的一個對象,
而不是一次構建一個結果列表。
數組
三、生成器函數
3-一、先看通常的函數:app
def func1(x): x += 1 return x func1(5) #函數的執行命令,而且接收函數的返回值。 print(func1(5)) #6
3-二、再看生成器函數:函數
def func1(x): x += 1 print(666) yield x x +=2 print(777) print(x) yield 'xiaobai' x +=3 g = func1(5) # 此時的func1(5)不會執行函數,由於它只是生成器函數對象 print(g) # <generator object func1 at 0x0000025E5D618780> print(g.__next__()) #666 6 print(next(g)) #777 8 xiaobai
3-三、yield與return的區別:
return:結束函數,給函數的執行者返回值
yield:不會結束函數,一個next對應一個yield,
執行yield上面的代碼並給 生成器對象.__next__() 返回值post
3-四、生成器函數與迭代器的區別
區別1:自定製的區別
迭代器由可迭代對象轉化而來,已經‘寫死了’this
l1 = [1,2,3,4,5] l1.__iter__()
生成器可用自定製函數來定製spa
def func1(x): x += 1 yield x x += 3 yield x x += 5 yield x g1 = func1(5) print(g1.__next__()) print(g1.__next__()) print(g1.__next__())
區別2:內存級別的區別。
迭代器是須要可迭代對象進行轉化,可迭代對象很是佔內存。
生成器直接建立,不須要轉化,從本質就節省內存。code
def func1(): for i in range(1000000): yield i g1 = func1() for i in range(50): print(g1.__next__()) #一個next取一次值,可用for循環取值
3-五、send與next
先看例子:對象
def func1(): print(1) count = yield 6 print(count) print(2) count1 = yield 7 print(count1) print(3) yield 8 g = func1() print(g.__next__()) #1 6 print(g.send('xiaobai')) #xiaobai 2 7 print(g.send('xiaigou')) #xiaogou 3 8
總結:
send與next同樣,也是對生成器取值(執行一個yield)的方法。
send能夠給上一個yield 傳值。
注意小坑:
1,第一次取值只能用next
2,最後一個yield不可能獲得send傳的值blog
3-六、生成器close()方法:
def fun(): for i in range(5): yield i g = fun() print(g.__next__()) print(g.__next__()) print(g.__next__()) g.close() # 直接把生成器的值取(刪)完了,後面就不能再取值 print(g.__next__()) # 報錯 a = (i for i in range(4)) print(a.__next__()) print(a.__next__()) a.close() print(a.__next__()) #報錯
3-七、生成器函數的應用例子
要製做一批量很大的衣服,用普通的函數只能一次所有制做完:
def cloth1(n): for i in range(n+1): print('衣服%s號' % i) cloth1(100000) #一次所有制做完了
而用生成器函數,須要製做多少就先製做多少:
def cloth2(n): for i in range(1,n+1): yield '衣服%s號' % i g = cloth2(10000) 先製做50件: for i in range(50): print(g.__next__()) #衣服1號,衣服2號,衣服3號...衣服50號 再製做50件: for i in range(50): print(g.__next__()) #衣服51號,衣服52號,衣服53號...衣服100號
2、列表推導式,生成器表達式
一、普通方法建立一個元素爲1到100的列表:
l1 = [] for num in range(1,101): l1.append(num) print(l1)
二、列表推導式:一行代碼幾乎搞定你須要的任何的列表。
2-一、兩種方式:
循環模式
篩選模式
2-二、循環模式:[變量(加工後的變量) for 變量 in iterable]
#1到100的列表 l = [i for i in range(1,101)] print(l) #[1,2,3,4...100] #python1到python15的列表 l2 = ['python%s' % i for i in range(1,16)] print(l2) #[python1,python2,python3...python15,] #1到10的平方 l3 = [i*i for i in range(1,11)] print(l3) #[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
2-三、篩選模式 [變量(加工後的變量) for 變量 in iterable if 條件]
#30之內的偶數 l4 = [i for i in range(1,31) if i % 2 == 0] print(l4) #[2, 4, 6, 8,10,...28, 30] #30之內能被3整除的數 l5 = [i for i in range(1,31) if i % 3 == 0] print(l5) #[3, 6, 9, 12, 15, 18, 21, 24, 27, 30] #30之內能被3整除的數的平方 l6 = [i**2 for i in range(1,31) if i % 3 == 0] print(l6) #[9, 36, 81, 144, 225, 324, 441, 576, 729, 900] #找出列表中含有兩個'e'的元素 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] l7 = [j for i in names for j in i if j.count('e') == 2] print(l7) #['Jefferson', 'Wesley', 'Steven', 'Jennifer']
2-四、列表推導式優缺點
優勢:一行解決,方便。
缺點:容易着迷,不易排錯,不能超過三次循環。
列表推導式不能解決全部列表的問題,因此不要太刻意用。
三、生成器表達式:將列表推導式的[]換成()便可。
g = (i for i in range(100000000000)) print(g) #生成器表達式左邊的變量g是生成器對象 print(g.__next__()) # 0 print(g.__next__()) # 1 print(g.__next__()) # 2 上面代碼至關於: def func(): for i in range(100000000000): yield i g = func() #生成器對象 print(g.__next__()) print(g.__next__()) print(g.__next__())
四、擴展
4-一、字典推導式
# 例一:將一個字典的key和value對調 dic = {'a': 10, 'b': 34} new_dic = {dic[k]: k for k in dic} print(new_dic) # 結果: # {10: 'a', 34: 'b'} # 例二:合併大小寫對應的value值,將k統一成小寫 dic = {'a': 10, 'b': 34, 'A': 7, 'Z': 3} new_dic = {k.lower():dic.get(k.lower(),0) + dic.get(k.upper(),0) for k in dic} print(new_dic) # 結果: # {'a': 17, 'b': 34, 'z': 3}
4-二、集合推導式
# 例一:計算列表中每一個值的平方,自帶去重功能 set1 = {x**2 for x in [1, -1, 2]} print(set1) # 結果: # {1, 4}
4-三、集合推導式和字典推導式的區別
相同點:外層都是使用大括號{} 不一樣點:返回的形式是 key:values 形式的就是字典,返回的形式是 values1,values2...形式的是集合 # 集合推導式 set1 = {x**2 for x in (1, -1, 2)} print(set1,type(set1)) # {1, 4} <class 'set'> # 字典推導式 dic1 = {x**2:x for x in (1, -1, 2)} print(dic1,type(dic1)) # {1: -1, 4: 2} <class 'dict'>
4-四、練習題
# 例1: 過濾掉長度小於3的字符串列表,並將剩下的轉換成大寫字母 l1 = [i.upper() for i in ['asdf','a','b','qwe'] if len(i) >= 3] print(l1) # 結果: # ['ASDF', 'QWE'] # 例2: 求(x,y)其中x是0-5之間的偶數,y是0-5之間的奇數組成的元組列表 l2 = [(x,y) for x in range(6) if x % 2 ==0 for y in range(6) if y % 2 == 1] print(l2) # 結果: # [(0, 1), (0, 3), (0, 5), (2, 1), (2, 3), (2, 5), (4, 1), (4, 3), (4, 5)] # 例3: 求M中3,6,9組成的列表 M = [[1,2,3],[4,5,6,24,3],[7,8,9,12,9]] l3 = [j for i in M for j in i for z in [3,6,9] if j / z == 1 ] print(l3) # 結果: # [3, 6, 3, 9, 9]