閉包函式,無參裝飾器,疊加多個裝飾器,有參裝飾器
阿新 • • 發佈:2020-07-21
一、閉包函式
閉包函式=函式巢狀定義+函式物件+名稱空間與作用域
閉包函式
閉:指的是該函式是定義在一個函式內部的函式
包:值得是該函式訪問了一個來自於外層函式的變數
為函式體傳參:
方案一:直接使用引數的形式傳遞
def wrapper(x): print(x) wrapper(111) wrapper(222)
方案二:把函式體想要的引數包給它
def outter(x): # x = 111 def wrapper(): # wrapper = 閉包函式的記憶體地址 print(x) return wrapper # 一定不要加括號# return 閉包函式的記憶體地址 f1 = outter(111) # f = 閉包函式的記憶體地址 f2 = outter(222) # f = 閉包函式的記憶體地址
二、無參裝飾器
1、什麼是裝飾器
器:工具
裝飾:為被裝飾者新增額外的功能
2、為何要有裝飾器
軟體一旦上線執行之後,就應該遵循開放封閉原則:
1、開放指的是對拓展新功能開放
2、封閉指的是對修改原始碼封閉
定義裝飾器的目的:
定義裝飾器就是為了在遵循1和2的前提下來為其他函式新增新功能的
ps:
不修改被裝飾物件指的是定義與呼叫都不能修改所以下述行為都違反了開放封閉原則:
1、修改被裝飾物件定義時的原始碼
2、修改被裝飾物件的呼叫方式
3、如何用裝飾器
3.1 被裝飾器物件index如下:
import time def index(x,y): time.sleep(1) print('index===>',x,y) index(1,2)
3.2為index新增新功能
#方案一:直接修改原始碼為被裝飾物件index新增新功能 #問題:修改了原始碼 import time def index(x,y): start_time = time.time() time.sleep(1) print('index===>',x,y) stop_time = time.time() print('run time is: %s' %(stop_time - start_time)) index(1,2)
# 方案二:找到所有呼叫index的位置,然新增程式碼 #問題:需要寫好多段重複程式碼 import time def index(x,y): time.sleep(1) print('index===>',x,y) start_time = time.time() index(1,2) stop_time = time.time() print('run time is: %s' %(stop_time - start_time))
#方案三:把裝飾功能寫到一個函式內 #問題:裝飾功能被寫死了,只能用來裝飾index函數了 import time def index(x,y): time.sleep(1) print('index===>',x,y) def wrapper(): start_time = time.time() index(1,2) stop_time = time.time() print('run time is: %s' %(stop_time - start_time)) wrapper()
#方案四:把wrapper函式內的index修改為引數的形式 #問題:直接為wrapper函式傳參的方案不行,因為原函式的呼叫 是在全域性呼叫index(1,2), 而現在的呼叫統一都變成了 wrapper(index),著修改被裝飾的呼叫方式 import time def index(x,y): time.sleep(1) print('index===>',x,y) def wrapper(func): start_time = time.time() func(1,2) stop_time = time.time() print('run time is: %s' %(stop_time - start_time)) wrapper(index)
#方案五:基於閉包函式把wrapper函式想要的引數包給它,然後基於函式物件把閉包函式wrapper返回到全域性,賦值給原函式名 #問題:把index偽裝成了wrapper,但偽裝的不夠像:引數的傳遞與原函式不一致 import time def index(x,y): time.sleep(1) print('index===>',x,y) def outter(func): # func = index def wrapper(): start_time = time.time() func(1,2) stop_time = time.time() print('run time is: %s' %(stop_time - start_time)) return wrapper index=outter(index) index()
#方案六:在方案五的基礎上基於*args,**kwargs把wrapper的引數偽裝成跟被裝飾函式一模一樣 #問題:返回值與原函式不一致 import time def index(x,y): time.sleep(1) print('index===>',x,y) def home(name): time.sleep(0.5) print('welcome %s to home page' %name) return 123 def outter(func): # func = index def wrapper(*args,**kwargs): start_time = time.time() func(*args,**kwargs) stop_time = time.time() print('run time is: %s' %(stop_time - start_time)) return wrapper index=outter(index) home=outter(home) # index(1,2) res=home('egon') print(res)
#方案七:在方案六的基礎上把wrapper函式的返回值與被裝飾函式保持一致 #問題:裝飾器的使用不夠簡潔 import time from functools import wraps def timmer(func): # func = index @wraps(func) def wrapper(*args,**kwargs): start_time = time.time() res=func(*args,**kwargs) stop_time = time.time() print('run time is: %s' %(stop_time - start_time)) return res return wrapper def index(x,y): time.sleep(1) print('index===>',x,y) def home(name): "home的文件註釋" time.sleep(0.5) print('welcome %s to home page' %name) return 123 index=timmer(index) home=timmer(home) # res=index(1,2) # print(res) # res=home('egon') # print(res) # print(home.__name__) # print(home.__doc__) help(home)
#方案八:在方案7的基礎上使用裝飾器的語法糖@符號讓裝飾器的使用變得簡潔 import time from functools import wraps def timmer(func): # func = index @wraps(func) def wrapper(*args,**kwargs): start_time = time.time() res=func(*args,**kwargs) stop_time = time.time() print('run time is: %s' %(stop_time - start_time)) return res return wrapper @timmer # index=timmer(index) def index(x,y): time.sleep(1) print('index===>',x,y) @timmer # home=timmer(home) def home(name): "home的文件註釋" time.sleep(0.5) print('welcome %s to home page' %name) return 123 res=index(1,2) res=home('egon')