一. 生成器python
生成器的實質就是迭代器, 在python中有三種方式得到生成器app
1. 生成器函數函數
2. 各類推導式實現生成器spa
3. 數據轉換也能夠得到生成器code
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 0x0000025256283A40>
以上兩段代碼執行的結果不同. 由於下面的代碼有yield,因此這個函數就是一個生成器函數.這個時候再執行這個函數,就不在是函數的執行了.而是獲取這個生成器.blog
因此要想運行這個函數,就要執行__next__()函數來執行函數內存
def func(): print("111") yield 222 gener = func() # 這個時候函數不會執行. 而是獲取到⽣生成器 ret = gener.__next__() # 這個時候函數纔會執行. yield的做⽤和return⼀樣. 也是返回數據 print(ret) #結果: # 111 # 222
能夠看到:return和yield執行的效果是同樣. 可是兩者是有區別的,yield是分段執行一個函數,return是直接中止執行函數pycharm
def func(): print("111") yield 222 print("333") yield 444 gener = func() ret = gener.__next__() print(ret) ret2 = gener.__next__() print(ret2) ret3 = gener.__next__() # 最後⼀一個yield執行完畢. 再次__next__()程序報錯, 也就是說和return⽆無關了了. print(ret3) #結果: #111 #222 #333 #444 #Traceback (most recent call last): # File "D:/pycharm項目/week3/day3/函數生成器.py", line 103, in #<module> # ret3 = gener.__next__() # 最後⼀一個yield執⾏行行完畢. 再次#__next__()程序報錯, 也就是 說. 和return⽆無關了了. #StopIteration
當程序運行完後⼀個yield. 那麼後面繼續進行__next__()程序會報錯. generator
生成器做用:
def cloth(): lst = [] for i in range(0, 100): lst.append("衣服"+str(i)) return lst cl = cloth() print(cl) #結果: #['衣服0', '衣服1', '衣服2', '衣服3', '衣服4', '衣服5', '衣服6', '衣服7', '衣服8', '衣服9', '衣服10', '衣服11', '衣服12', '衣服13', '衣服14', '衣服15', '衣服16', '衣服17', '衣服18', '衣服19', '衣服20', '衣服21', '衣服22', '衣服23', '衣服24', '衣服25', '衣服26', '衣服27', '衣服28', '衣服29', '衣服30', '衣服31', '衣服32', '衣服33', '衣服34', '衣服35', '衣服36', '衣服37', '衣服38', '衣服39', '衣服40', '衣服41', '衣服42', '衣服43', '衣服44', '衣服45', '衣服46', '衣服47', '衣服48', '衣服49', '衣服50', '衣服51', '衣服52', '衣服53', '衣服54', '衣服55', '衣服56', '衣服57', '衣服58', '衣服59', '衣服60', '衣服61', '衣服62', '衣服63', '衣服64', '衣服65', '衣服66', '衣服67', '衣服68', '衣服69', '衣服70', '衣服71', '衣服72', '衣服73', '衣服74', '衣服75', '衣服76', '衣服77', '衣服78', '衣服79', '衣服80', '衣服81', '衣服82', '衣服83', '衣服84', '衣服85', '衣服86', '衣服87', '衣服88', '衣服89', '衣服90', '衣服91', '衣服92', '衣服93', '衣服94', '衣服95', '衣服96', '衣服97', '衣服98', '衣服99'] def cloth(): for i in range(0, 10000): yield "衣服"+str(i) cl = cloth() print(cl.__next__()) print(cl.__next__()) print(cl.__next__()) print(cl.__next__()) #結果: # 衣服0 # 衣服1 # 衣服2 # 衣服3
區別: 第一種是將循環的內容直接所有拿出來,很佔用內存. 第二種使用生成器,一個__next__函數只拿出一個,以後循環中止在當前位置,下一個再取值再從中止位置繼續向前取值.
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) #結果: # 我吃什麼啊 # 饅頭 # a= 胡辣湯 # 大餅 # b= 狗糧 # 韭菜盒子 # c= 貓糧 # GAME OVER
send和__next__()區別: 1. send和next()都是讓生成器向下走⼀次 2. send能夠給上⼀個yield的位置傳遞值, 不能給後⼀個yield發送值. 在第⼀次執行生成器代碼的時候不能使用send()
生成器能夠使用for循環來循環獲取內部的元素:
def func(): print(111) yield 222 print(333) yield 444 print(555) yield 666 gen = func() for i in gen: print(i) #結果: # 111 # 222 # 333 # 444 # 555 # 666
二. 列表推導式
列表推導式:最終給的是列表
語法: [最終結果(變量) for 變量 in 可迭代對象]
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'] 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']
列表推導式是經過⼀行來構建你要的列表, 列表推導式看起來代碼簡單. 可是出現錯誤以後很難排查.
⽣生成器表達式和列表推導式的語法基本上是⼀樣的. 只是把[]替換成()
g = (i for i in range(10)) print(g) #打印結果是一個生成器 #結果: #<generator object <genexpr> at 0x0000029147073A40> gen = ("麻xx我第%s次愛你" % i for i in range(10)) for i in gen: #遍歷生成器內容 print(i) #結果: #麻xx我第0次愛你 #麻xx我第1次愛你 #麻xx我第2次愛你 #麻xx我第3次愛你 #麻xx我第4次愛你 #麻xx我第5次愛你 #麻xx我第6次愛你 #麻xx我第7次愛你 #麻xx我第8次愛你 #麻xx我第9次愛你
生成器表達式能夠進行篩選:
lst = [i for i in range(1,101) if i % 3 == 0] print(lst) #結果: #[3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99] lst = [i*i for i in range(1,100) 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] 找出下列名字中帶有兩個'e'的. names = [['Tom', 'Billy', 'Jefferson' , 'Andrew' , 'Wesley' , 'Steven' , 'Joe'],['Alice', 'Jill' , 'Ana', 'Wendy', 'Jennifer', 'Sherry' , 'Eva']] lst = [ii for i in names for ii in i if ii.count('e') ==2] print(lst) #結果: #['Jefferson', 'Wesley', 'Steven', 'Jennifer']
生成器表達式和列表推導式的區別:
1. 列表推導式比較耗內存. ⼀次性加載. 生成器表達式幾乎不佔用內存. 使用的時候才分配和使用內存
2. 獲得的值不⼀樣. 列表推導式獲得的是⼀個列表. 生成器表達式獲取的是⼀個生成器.
生成器的惰性機制:生成器只有在訪問的時候才取值. 說白了就是找他要他纔給值,不要的話,他是不會執行的
總結:
推導式有列表推導式,字典推導式,集合推導式,沒有元組推導式
生成器表達式:(結果 for 變量 in 可迭代對象 if 條件篩選)
生成器表達式能夠直接獲取到生成器對象,生成器能夠直接進行for循環. 生成器具備惰性機制