一、閉包: 保護數據安全、保護數據乾淨性。面試
二、閉包的定義:在嵌套函數內、使用非全局變量(且不使用本層變量)數組
將嵌套函數返回安全
閉包的目的:要接受被裝飾的函數和被裝飾函數須要的參數
三、閉包舉例子:數據結構
def func():
a = 10
def foo():
print(a)
return foo
f = func()
f()
結果:10
四、驗證閉包函數:__closure__
def func():
a = 10 #自由變量
def foo():
print(a) #打印a有一個綁定關係
return foo
f = func()
print(f.__closure__)
結果:(<cell at 0x0000000001E285E8: int object at 0x00000000525A8190>,)
五、函數體執行完之後將函數體開闢的空間都釋放掉了
六、模擬買車求平均價版一:
lst = []
def buy_car(price):
lst.append(price)
arg = sum(lst) / len(lst)
print(arg)
buy_car(120000) #週一
buy_car(240000) #週二
buy_car(10000000) #週三
buy_car(5500000) #週四
buy_car(120000) #週五
buy_car(50000000) #週六
buy_car(5000000) #週日
結果: 120000.0
180000.0
3453333.3333333335
3965000.0
3196000.0
10996666.666666666
10140000.0閉包
七、版二:查看閉包函數裏面的自由變量__code__.co_freevars:app
def buy_car():
lst = []
def func(price):
lst.append(price)
arg = sum(lst) / len(lst)
print(arg)
return func
f = buy_car()
print(f.__code__.co_freevars)
f(1)
f(2)
f(3)
f(4)
f(5)
結果:('lst',)
1.0
1.5
2.0
2.5
3.0函數
八、查看閉包函數裏面的局部變量__code__.co_varnames:工具
def buy_car():
lst = []
def func(price):
lst.append(price)
arg = sum(lst) / len(lst)
print(arg)
return func
f = buy_car()
print(f.__code__.co_freevars)
print(f.__code__.co_varnames)
f(1)
f(2)
f(3)
f(4)
f(5)
結果:('lst',)
('price', 'arg')
1.0
1.5
2.0
2.5
3.0spa
九、沒有將嵌套的函數返回也是一個閉包、可是這個閉包不是一個可以使用的閉包:3d
def func():
a = 10
def foo():
print(a)
print(foo.__closure__)
func()
# 結果:(<cell at 0x00000000021785E8: int object at 0x00000000592F8190>,)
十、閉包就是須要打開兩次而已:
十一、如下也是一個閉包:
def wrapper(a,b):
#a = 1 #隱形傳參/隱形定義變量和後續的隱形接收傳參
#b = 2
def inner():
print(a)
print(b)
return inner
a = 2
b = 3
ret = wrapper(a,b)
print(ret.__closure__)
# 結果:(<cell at 0x0000000001E185E8: int object at 0x00000000592F8090>, <cell at 0x0000000001E18618: int object at 0x00000000592F80B0>)
十二、閉包的應用場景:
一、裝飾器
二、防止數據被誤改動
裝飾器的本質就是閉包
1三、生成器的本質就是迭代器:
1四、開放封閉原則:
一、對擴展開放--支持增長新功能
二、對修改源代碼是封閉,對調用方式是封閉的
1五、裝飾(在原有的基礎上額外添加功能)器--工具:
1六、裝飾器運行圖:
1七、語法糖:語法糖必須放在被裝飾的函數正上方
語法糖的本質就是index = run_time(index)
函數名能夠當作另外一個函數參數
函數名能夠當作另外一個函數的返回值
函數名能夠當作值賦值給變量
import time
def run_time(f):
def inner():
start_time = time.time() #被裝飾函數以前
f()
print(time.time() - start_time) #被裝飾函數以後
return inner
@run_time
def index():
print("is index 海綿")
index()
1八、有參裝飾器:
import time
def run_time(f): #f接收的是被裝飾的函數名
def inner(*args,**kwargs): #被裝飾的函數須要的參數
print("外掛開啓")
f(*args,**kwargs)
print("外掛關閉")
return inner
@run_time
def index(user,pwd,hero):
print("打開遊戲")
print(f"登陸{user}和{pwd}")
print(f"選擇英雄:{hero}")
print("遊戲中")
print("遊戲結束")
index("meet","123456","草叢倫")
1九、有參裝飾器有返回值時:
def run_time(f): #f接收的是被裝飾的函數名
def inner(*args,**kwargs): #被裝飾的函數須要的參數
print("外掛開啓")
ret = f(*args,**kwargs)
print("外掛關閉")
return ret
return inner
@run_time
def index(user,pwd,hero):
print("打開遊戲")
print(f"登陸{user}和{pwd}")
print(f"選擇英雄:{hero}")
print("遊戲中")
return "遊戲結束"
print(index("meet","123456","草叢倫"))
20、標準版裝飾器:
def wrapper(func):
def inner(*args,**kwargs):
"""執行被裝飾函數前的操做"""
func(*args,**kwargs)
"""執行被裝飾函數後的操做"""
return inner
@wrapper
def index():
print("is index")
index()
2一、未來有可能會問:
語法糖要接受的變量就是語法糖下面的函數名、參數就是語法糖下面的函數名、調用的方式就是看調用的哪一個語法糖
def func(args):
print("新加了一個功能")
return args
@func #index = func(index)
def index():
print(2)
index()
結果: 新加了一個功能
2
2二、做業題:
# 一、用內置函數或者和匿名函數結合作出# 二、用map來處理下述l,而後用list獲得一個新的列表,列表中每一個人的名字都是sb結尾l=[{'name':'alex'},{'name':'y'}]print(list(map(lambda x:x["name"] + "sb",l)))# 三、用filter來處理,獲得股票價格大於20的股票名字# shares={# 'IBM':36.6,# 'Lenovo':23.2,# 'oldboy':21.2,# 'ocean':10.2,# }# print(list(filter(lambda i:shares[i] > 20,shares)))# 四、有下面字典,獲得購買每隻股票的總價格,並放在一個迭代器中。# 結果:list一下[9110.0, 27161.0,......]# portfolio = [# {'name': 'IBM', 'shares': 100, 'price': 91.1},# {'name': 'AAPL', 'shares': 50, 'price': 543.22},# {'name': 'FB', 'shares': 200, 'price': 21.09},# {'name': 'HPQ', 'shares': 35, 'price': 31.75},# {'name': 'YHOO', 'shares': 45, 'price': 16.35},# {'name': 'ACME', 'shares': 75, 'price': 115.65}]print(list(map(lambda i:i["shares"] * i["price"],portfolio)))# 五、仍是上面的字典,用filter過濾出單價大於100的股票。print(list(filter(lambda x:x["price"] > 100,portfolio)))# 六、有下列三種數據類型,# l1 = [1,2,3,4,5,6]# l2 = ['oldboy','alex','wusir','太白','日天']# tu = ('**','***','****','*******')# 寫代碼,最終獲得的是(每一個元祖第一個元素>2,第三個*至少是4個。)# [(3, 'wusir', '****'), (4, '太白', '*******')]# 七、有以下數據類型(實戰題):# l1 = [{'sales_volumn': 0},# {'sales_volumn': 108},# {'sales_volumn': 337},# {'sales_volumn': 475},# {'sales_volumn': 396},# {'sales_volumn': 172},# {'sales_volumn': 9},# {'sales_volumn': 58},# {'sales_volumn': 272},# {'sales_volumn': 456},# {'sales_volumn': 440},# {'sales_volumn': 239}]# 將l1按照列表中的每一個字典的values大小進行排序,造成一個新的列表。print(sorted(l1,key=lambda x:x["sales_volumn"]))# 八、有以下數據結構,經過過濾掉年齡大於16歲的字典# lst = [{'id':1,'name':'alex','age':18},# {'id':1,'name':'wusir','age':17},# {'id':1,'name':'taibai','age':16},]print(list(filter(lambda x:x["age"] > 16,lst)))# 九、有以下列表,按照元素的長度進行升序# lst = ['天龍八部','西遊記','紅樓夢','三國演義']print(sorted(lst,key = len))# 十、有以下數據,按照元素的年齡進行升序# lst = [{'id':1,'name':'alex','age':18},# {'id':2,'name':'wusir','age':17},# {'id':3,'name':'taibai','age':16},]print(sorted(lst,key=lambda x:x["age"]))# 十一、看代碼敘說,兩種方式的區別# lst = [1,2,3,5,9,12,4]# lst.reverse() #原地修改# print(lst)# print(list(reversed(lst))) #新開闢了一個列表# 十二、求結果(面試題)# v = [lambda :x for x in range(10)] #首先這個一總體是列表推導式# print(v)#結果是10個函數的內存地址:[<function <listcomp>.<lambda> at 0x000000000221AB70>, <function <listcomp>.<lambda> at 0x000000000221AA60>, <function <listcomp>.<lambda> at 0x000000000221AC80>, <function <listcomp>.<lambda> at 0x000000000221ABF8>, <function <listcomp>.<lambda> at 0x000000000221AD08>, <function <listcomp>.<lambda> at 0x000000000221AD90>, <function <listcomp>.<lambda> at 0x000000000221AE18>, <function <listcomp>.<lambda> at 0x000000000221AEA0>, <function <listcomp>.<lambda> at 0x000000000221AF28>, <function <listcomp>.<lambda> at 0x0000000002223048>]# print(v[0])#從10個函數內存地址裏面拿到第一個函數的內存地址:[<function <listcomp>.<lambda> at 0x000000000221AB70># print(v[0]()) #第一個函數的內存地址加括號運行不用加參數、由於lambda函數裏面沒有形參、x是for循環的最後一個數9# 1三、求結果(面試題)# v = (lambda :x for x in range(10))# print(v) #生成器的內存地址# print(v[0]) #報錯生成器對象不可訂閱# print(v[0]()) #報錯生成器對象不可訂閱# print(next(v)) #函數的內存地址# print(next(v)()) #運行結果是1# 1四、map(str,[1,2,3,4,5,6,7,8,9])輸出是什麼? (面試題)#結果:<map object at 0x00000000021C77B8> ## 1五、有一個數組[34,1,2,5,6,6,5,4,3,3]請寫一個函數,找出該數組中沒有重複的數的總和(上面數據沒有重複的總和爲1+2+34=40)(面試題)#for循環寫法:lst = [34,1,2,5,6,6,5,4,3,3]num = 0for i in lst: if lst.count(i) == 1: num += iprint(num)#sum求和:print(sum([x for x in lst if lst.count(x) == 1]))#filter過濾:print(sum(list(filter(lambda x:lst.count(x) == 1,lst))))# 1六、求結果:(面試題)# def num():# return [lambda x:x**i for i in range(4)]# print([m(2)for m in num()])# 結果:[8, 8, 8, 8]# 1七、看代碼寫結果:# def wrapper(f):# def inner(*args, **kwargs):# print(111)# ret = f(*args, **kwargs)# print(222)# return ret# return inner# def func():# print(333)# print(444)# func()# print(555)# 1八、編寫裝飾器, 在每次執行被裝飾函數以前打印一句’每次執行被裝飾函數以前都得先通過這裏’。def wrapper(f): def innder(*args,**kwargs): print("每次執行被裝飾函數以前都得先通過這裏") ret = f(*args,**kwargs) print("嘿嘿嘿") return innder@wrapper #func = wrapper(func)def func(): print("i am name 張達")func()# 1九、爲函數寫一個裝飾器,把函數的返回值 + 100而後再返回。def wrapper(func): def inner(*args,**kwargs): return func(*args,**kwargs) + 100 return inner@wrapperdef func(): return 7result = func()print(result)# 2三、請實現一個裝飾器,每次調用函數時,將被裝飾的函數名以及調用被裝飾函數的時間節點寫入文件中。可用代碼以下:def wrapper(func): def inner(*args,**kwargs): import time struct_time = time.localtime() time_str = time.strftime("%Y-%m-%d %H:%M:%S",struct_time) #獲取當前時間節點 with open("info","a",encoding="utf-8") as f: f.write(f"時間:{time_str} 函數名:{func.__name__}\n") func(*args,**kwargs) print("寫入成功!") return inner@wrapperdef func(): print(func.__name__) #如今看到的func已是inner了 print("我被執行了")func()# inner# 我被執行了# 寫入成功!