1. 函數名 -> 第一類對象 函數名就是變量名. 函數能夠賦值 函數能夠做爲集合類的元素 函數能夠做爲參數傳遞 函數能夠做爲返回值返回 2. 閉包 語法: 內層函數對外層函數的局部變量的使用 def wrapper(): name = "" def inner(): return name return inner 如何查看一個函數是不是閉包 函數名.__closure__ 有值就是閉包. None就不是閉包 優勢: 1. 保護變量不被侵害 (javascript) 2. 可讓一個變量常駐內存 3. 迭代器 在數據中包含了__iter__是一個可迭代對象. for循環內部 it = lst.__iter__() while 1: try: it.__next__() except StopIteration: break 特色: 1. 節省內存 2. 惰性機制 3. 只能向前, 不能反覆 意義: 統一數據類型的遍歷工做 官方查看xxx是迭代器, 可迭代對象 from collections import Iterable, Iterator isinstance(對象, Iterable) isinstance(對象, Iterator) 迭代器必定可迭代 -> for循環 可迭代的不必定是迭代器
1. 生成器 本質就是迭代器. 一個一個的建立對象 建立生成器的方式: 1. 生成器函數 2. 經過生成器表達式來獲取生成器 3. 類型轉換(看不到) 2. 生成器函數 (重點) 生成器函數中包含 yield , 返回數據和return差很少. return會當即結束這個函數的執行 yield 能夠分段的執行一個函數 生成器函數在執行的時候返回生成器. 而不是直接執行此函數 能向下執行的兩個條件: __next__(), 執行到下一個yield send(), 執行到下一個yield, 給上一個yield位置傳值 全部的生成器都是迭代器均可以直接使用for循環 均可以使用list()函數來獲取到生成器內全部的數據 生成器(##每次調用生成器函數就建立了一個生成器)中記錄的是代碼而不是函數的運行 def func(): print("個人天哪 ") yield "寶寶" △(理解記憶) gen = func() # 建立生成器. 此時運行會把生成器函數中的代碼記錄在內存,當執行到__next__(), 運行此空間中的代碼, 運行到yield結束. 優勢: 節省內存, 生成器自己就是代碼. 幾乎不佔用內存 特色: 惰性機制, 只能向前. 不能反覆 3. 各類推導式 (詭異) 列表推導式 [結果 for循環 if] 字典推導式 {結果(k:v) for循環 if} 集合推導式 {結果(k) for循環 if} 4. 生成器表達式 (重點) (結果 for循環 if) 老師講的所謂的與生成器函數相比 生成器表達式是一次性的.是指生成器函數經過gen = func()建立生成器 以後能夠反覆的調用生成器,
而生成器表達式一次執行完以後,下次執行還要從新寫一次.
什麼是生成器.生成器實質就是迭代器.
在python中有三種方式來獲取生成器:
1.經過生成器函數
2.經過各類推導式來實現生成器
3.經過數據的轉換也能夠獲取生成器javascript
首先,咱們先看一個很簡單的函數:java
def func(): print("111") return 222 ret = func() print(ret) 結果: 111 222
將函數中的return換成yield就是生成器python
def func() : print("111") yield 222 ret = func() print(ret) 結果: <generator object func at 0x10567ff68>
運行的結果和_上面不同. 爲何呢.因爲函數中存在了yield.那麼這個函數就是一個生成器函數.這個時候.咱們再執行這個函數的時候.就再也不是函數的執行了.而是獲取這個生成器.如何使用呢?想一想迭代器.生成器的本質是迭代器.因此.咱們能夠直接執行__next__()來執行如下生成器.面試
def func(): printC111") yield 222 gener = func() # 這個時候函數不會執行,而是獲取到生成器 ret = gener.__next___ () # 這個時候函數纔會執行,yield的做用和return- 樣,也是返回數據 print(ret) 結果: 111 222
那麼咱們能夠看到, yield和return的效果是-樣的.有什麼區別呢? yield是分段來執行一個函數. return呢?直接中止執行函數.閉包
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 Traceback (most recent call last): 222 333 File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 55, in <module> 444 ret3 = gener.__ .next__ .(0) # 最後一個yield執行完畢,再次__next__()程序報錯, 也就是說,和return無關了 StopIteration
當程序運行完最後一個yield.那麼後面繼續進行__next__()程序會報錯.
好了生成器說完了.生成器有什麼做用呢?咱們來看這樣一個需求. 老男孩向JACK JONES訂購10000套學生服. JACK JONES就比較實在.直接造出來10000套衣服.app
def cloth(): lst =[] for i in range(0, 10000): lst. append("衣服" +str(i)) return lst cl = cloth()
可是呢,問題來了.老男孩如今沒有這麼多學生啊.一次性給我這麼多.我往哪裏放啊.很尷尬啊.最好的效果是什麼樣呢?我要1套.你給我1套.一共1000套.是否是最完美的ide
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__())
區別:第一種是直接一次性所有拿出來,會很佔用內存.第二種使用生成器,-次就-個,用多少生成多少.生成器是一個一個的指向下一個.不會回去,__next__()到哪, 指針就指到哪兒.下一次繼續獲取指針指向的值
接下來咱們來看send方法, send和__next__()同樣均可以讓生成器執行到下一個yield.函數
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)
send和__next__()區別:
1. send和next()都是讓生成器向下走-次
2. send可 以給上一個yield的位置傳遞值,不能給最後-個yield發送值. 在第一次執行生成器代碼的時候不能使用send()spa
生成器可使用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
首先咱們先看一下這樣的代碼,給出一個列表,經過循環,向列表中添加1-14 :
lst=[] for i in range(1,15): lst . append(i) print(lst)
替換成列表推導式:
lst = [i for i in range(1, 15)] print(lst)
列表推導式是經過-行來構建你要的列表,列表推導式看起來代碼簡單.可是出現錯誤以後很難排查.
列表推導式的經常使用寫法:
[結果 for 變量 in 可迭代對象]
例.從python1期到python14期寫入列表Ist:
lst = ['python%s' % i for i in range(1,15)] print(lst)
咱們還能夠對列表中的數據進行篩選
篩選模式:
[結果 for 變量 in 可迭代對象 if條件]
#獲取1-100內全部的偶數 lst = [i for i in range(1, 100) if i % 2 == 0] print(lst)
生成器表達式和列表推導式的語法基本上是同樣的.只是把[]替換成()
gen = (i for i in range(10)) print(gen) 結果: <generator object <genexpr> at 0x106768f10>
打印的結果就是一個生成器.咱們可使用for循環來循環這個生成器:
gen = ("麻花藤我第%s次愛你」% i for i in range(10)) for i in gen: print(i)
生成器表達式也能夠進行篩選:
#獲取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(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']] #不用推導式和表達式 result =[] for first in names: for name in first: if name.count("e") >= 2: result.append( name) print(result) #推導式 gen = (name for first in names for name in first if name.count("e") >= 2) for name in gen: print(name)
生成器表達式和列表推導式的區別:
1.列表推導式比較耗內存. -次性加載.生成器表達式幾乎不佔用內存.使用的時候才分配和使用內存
2.獲得的值不- -樣.列表推導式獲得的是一個列表.生成器表達式獲取的是一個生成器.
舉個栗子.
一樣-籃子雞蛋. 列表推導式:直接拿到-籃子雞蛋.生成器表達式:拿到-個老母雞.須要雞蛋就給你下雞蛋.
生成器的惰性機制:生成器只有在訪問的時候才取值.說白了,你找他要他纔給你值,不找他要,他是不會執行的.
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同理
深坑==>生成器.要值得時候纔拿值
根據名字應該也能猜到.推到出來的是字典
#把字典中的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[訂] for i in range(len(lst1))} print(dic)
集合推導式能夠幫咱們直接生成一個集合. 集合的特色:無序,不重複.因此集合推導式自帶去重功能
lst = [1, -1, 8, -8,12] #絕對值去重 s = {abs(i) for i in lst} print(s)
總結:推導式有,列表推導式,字典推導式,集合推導式,沒有元組推導式
生成器表達式: (結果 for 變量 in 可迭代對象 if條件篩選)
生成器表達式能夠直接獲取到生成器對象.生成器對象能夠直接進行for循環.生成器具備惰性機制.
一個面試題.難度係數0000000顆星:
def add(a, b): return a + b def test(): for i in range(4): yield i g = test() for n in [2, 10]: g=(add(n,i) for i in g) print(list(g))
友情提示:惰性機制,不到最後不會拿值
這個題要先讀一下. 而後本身分析出結果.最後用機器跑一下
# 生成器經典題 def add(a, b): # 相加 return a + b def test(): # 生成器函數 0 1 2 3 for i in range(4): yield i g = test() # 建立生成器 for n in [2, 10]: g = (add(n, i) for i in g) print(list(g)) # 結果:[20,21,22,23] # 解題思路:惰性機制(#有人要值才執行);生成器記錄的是代碼(#只有在執行的時候纔會帶入變量的值) # 1,拆分for循環 n = 2 g = (add(n, i) for i in g) n = 10 g = (add(n, i) for i in g) # 2,將g = test()代入,並層層帶入 n = 2 g = (add(n, i) for i in test()) n = 10 g = (add(n, i) for i in (add(n, i) for i in test())) # 3,拿值的時候帶入變量的值去執行 print(list(g)) # 拿值list==>for==>__next__() # 此時的 g = (add(n, i) for i in (add(n, i) for i in test())) # 代入變量的值 # n = 10 # test()的取值範圍是[0,1,2,3] # 因此 # list(g) == [(add(10, i) for i in (add(10, i) for i in [0,1,2,3]))]==10*2+[0,1,2,3] # == [(add(10, i) for i in [10,11,12,13]] # == [20,21,22,23] # 小結規律: # test()的取值範圍是初始範圍 # 要拿值時候的n的值是要帶入的值 # for循環決定循環的次數,循環幾回就累加幾回,也就是要加幾個n的值 # 改變1 def add(a, b): # 相加 return a + b def test(): # 生成器函數 0 1 2 3 for i in range(4): yield i g = test() # 建立生成器 for n in [2, 10]: g = (add(n, i) for i in g) n = 5 print(list(g)) # 結果:[10,11,12,13] # 解題思路同上,最終拿到 # g = (add(n, i) for i in (add(n, i) for i in test())) # 而此時n=5,帶入獲得 5*2+[0,1,2,3]=[10,11,12,13] # 改變2 def add(a, b): # 相加 return a + b def test(): # 生成器函數 0 1 2 3 for i in range(4): yield i g = test() # 建立生成器 for n in [2, 10, 5]: g = (add(n, i) for i in g) print(list(g)) # 解題思路同上,最終拿到 n = 2 g = (add(n, i) for i in g) n = 10 g = (add(n, i) for i in g) n = 5 g = (add(n, i) for i in g) # 層層代入獲得: n = 2 g = (add(n, i) for i in test()) n = 10 g = (add(n, i) for i in (add(n, i) for i in test())) n = 5 g = (add(n, i) for i in (add(n, i) for i in (add(n, i) for i in test()))) # 代入數據獲得: list(g) = (add(5, i) for i in (add(5, i) for i in (add(5, i) for i in [0,1,2,3])))=5*3+[0,1,2,3]=[15,16,17,18]
區別生成器表達式和列表生成式:
def add(a, b): return a + b def test(): # print("123") for i in range(4):#[0,1,2,3] yield i g = test() for n in [2, 10, 5]: # 第一種:生成器表達式 # g = (add(n, i) for i in g) # [15, 16, 17, 18]在生成器表達式內部的生成器或者生成器表達式是不會執行的,直到外部的生成器有人找它要值 # 第二種:列表生成式,是會直接帶入執行的 g = [add(n, i) for i in g] # [17, 18, 19, 20] #第一種: # 對for循環進行等價替換,所有代入n=5 # g1 = (add(5, i) for i in g) #g = test()= [0,1,2,3] # g2 = (add(5, i) for i in g1) # g3 = (add(5, i) for i in g2) #第二種: # 對for循環進行等價替換,分別代入n=2,10,5 # g1 = (add(2, i) for i in g) #g = test()= [0,1,2,3] # g2 = (add(10, i) for i in g1) # g3 = (add(5, i) for i in g2) print(list(g))