Day59 Python--閉包&裝飾器
阿新 • • 發佈:2018-10-31
一,函式知識點回顧
def func(): pass print(func) #函式名對應記憶體地址 a = func #可以賦值給變數 a() def func2(arg): #可以做引數 arg() func2(func) def func3(): #可以做返回值 def fun4(): pass return func4 lis = [func,func2,func3,func4] #可以做容器物件的元素 for i in lis: i()
二,閉包
定義:如果一個內層函式包含了對外層函式變數的引用,那這個內層函式就是閉包
def wrapper(name): def inner(): print(name) #相當內層函式的空間裡保留了name變數的引用並且指向當初傳入的實參 return inner ret = wrapper('123') #當函式執行時,Python直譯器會開闢一塊記憶體(區域性名稱空間)來儲存這個函式裡面的內容,這個時候,Python直譯器才關注函式裡面變數名和值之間對應的關係,包括內層函式內的內容 del wrapper ret() # 指向inner的記憶體地址 wrapper('123') #報錯:NameError: name 'wrapper' is not defined閉包如何儲存區域性變數的資料
#靈魂三問1 def func1(): num = 100 def func2(arg): print(arg) func2(num) #通過傳參的方式,向內層函式傳遞資料 func1() #靈魂三問2 def func1(): num = 100 def func2() print(num) #內層函式的作用域裡沒有num,會自動往外層函式的作用域去找 func2() func1() #靈魂三問3 def func1(num):看起來好像很牛b的閉包靈魂三問def func2(): print(num) #內層函式的作用域路沒有num,會自動往外層函式的作用域去找 func2() func1()
#內層函式+其外層函式變數的引用 def func1(name): def func2(): print(name) return func2 ret = func1('alex') ret() #非閉包 def func1(): def func2(): def func3(): def func4(): pass return func4 return func3 return func2 ret1 = func1() #func2 ret2 = ret1() #func3 ret3 = ret2() #func4 ret3()閉包的變形
三,裝飾器初識
#裝飾器的定義:
既不想直接修改原來的函式,也不想修改函式的呼叫方式,還要加新功能的時候,可以使用裝飾器 def wrapper(func): def inner(*args,**kwargs): print('新功能') func(*args,**kwargs) return inner
#global_func = wrapper(global_func) 內層的inner函式,引用了func,func -指向-> global_func
@wrapper #相當於把被裝飾的函式當成引數傳給a,然後把返回值再賦值給被裝飾的函式名
def global_func(): pass
global_func() #相當於呼叫了內層函式inner
四,裝飾器進階
1.裝飾帶引數的函式
# 裝飾帶引數的函式 def wrapper(func): def inner(*args, **kwargs): # 實際執行函式的引數 print('開始') r = func(*args, **kwargs) print(r) print('結束') return r return inner @wrapper def my_sum(x, y): print('我是my_sum函式') return x + y ret = my_sum(10, 20) # inner(10, 20) print(ret)
2.裝飾帶返回值的函式
# 裝飾帶返回值的函式 def wrapper(func): def inner(): print('開始') r = func() # 拿到原來函式的返回值 print('結束') return r return inner @wrapper def f1(): print('我是f1') return 100 ret = f1() #實際上是執行了inner內層函式,如果inner內層沒用renturn返回值,則f1也沒用返回值
3.帶引數的裝飾器 *****
def mougehanshu(arg): def wrapper(func): def inner(*args, **kwargs): print('歡迎VIP使用者進入{}專欄!'.format(arg)) func(*args, **kwargs) return inner return wrapper # wrapper = mougehanshu() #@mougehans(引數) 相當於 @wrapper @mougehanshu('電影') # 相當於mougehanshu()執行後返回wrapper def movie(): print('這是電影專欄!') @mougehanshu('體育') # @wrapper def sport(): print('這是體育專欄!')
4.多個裝飾器裝飾同一個函式 *****
def foo1(func): print("d1") def inner1(): print("inner1") return "<i>{}</i>".format(func()) return inner1 def foo2(func): print("d2") def inner2(): print("inner2") return "<b>{}</b>".format(func()) return inner2 @foo1 #f1 = foo1(foo2(f1))=foo1(inner2,列印d2) = inner1 列印'd1' @foo2 #執行foo2(f1) =inner2 列印'd2' def f1(): return "我是f1" ret = f1() print(ret) # f1 = foo2(f1) --> inner2 # f1 = foo1(inner2) --> inner1 ↓↓ #執行流程分析: #f1() == inner1()->列印'inner1'->return "<i>{}</i>".format(inner2()) #inner2() -> 列印'inner2'->return "<b>{}</b>".format(f1()) #f1() -> return "我是f1" ↓↓ print(ret) ---> '<i><b>我是f1</b></i>'
5.裝飾器修復技術 ****
# 裝飾器修復技術 from functools import wraps # Flask框架的時候用得上 def wrapper(func): @wraps(func) def inner(*args, **kwargs): print('這是新功能') func(*args, **kwargs) return inner @wrapper def f1(arg1, arg2): """ 這裡寫這個函式是做什麼的 :param arg1: 這個引數是什麼型別的 :param arg2: 這個引數是什麼型別 :return: None """ print('嘿嘿嘿') print(f1.__doc__) print(f1.__name__) #若不修復的話,f1實際是指向inner的記憶體空間, #f1.__doc__ 相當於 inner.__doc__中的內容 #f1.__name__ 相當於 inner.__name__中的內容
五,裝飾器究極進階
1.類裝飾器
2.裝飾類