python閉包函式和裝飾器
阿新 • • 發佈:2022-03-18
python閉包函式和裝飾器
閉包函式
閉包的特點就是內部函式引用了外部函式中的變數
# 閉包函式的兩大特徵
1.閉:定義在函式內部的函式
2.包:內部函式使用了外層函式名稱空間中的名字
#程式碼示例:
def outer():
name = 'python'
def inner():
print(name)
return inner
index = outer()
index()
'閉包中被內部函式引用的變數,不會因為外部函式結束而被釋放掉,而是一直存在記憶體中,知道內部函式被呼叫結束'
閉包函式的實際應用
#閉包好處: 1. 保護變數 2. 可以讓一個變數常駐記憶體 3. 迭代器 __iter__() 可迭代物件. 獲取迭代器 __next__() + __iter__() 迭代器 特點: 1. 惰性機制 2. 只能向前 3. 節省記憶體 for迴圈的內部就是迭代器 '閉包函式是給函式體傳參的另外一種方式' #函式體傳參的方式1:形參 def index(username): print(username) index('mark') #函式體傳參的方式2:閉包 def outer(): username = 'jason' def index(): print(username) return index res = outer()
裝飾器簡介
# 裝飾器的本質 在不改變被裝飾物件原有的'呼叫方式'和'內部程式碼' 的情況下給被裝飾物件新增新的功能 # 裝飾器的原則 對擴充套件開放 對修改封閉 #實質: 是一個函式 #引數:是你要裝飾的函式名(並非函式呼叫) #返回:是裝飾完的函式名(也非函式呼叫) #作用:為已經存在的物件新增額外的功能 #特點:不需要對物件做任何的程式碼上的變動 # 程式碼示例: import time def index(): time.sleep(3) print('from index') '''給index函式增加了一個統計執行時間的功能''' start_time = time.time() # 函式執行之前獲取一個時間戳 index() end_time = time.time() # 函式執行之後獲取一個時間戳 print(end_time - start_time) # 兩個時間戳的差值就是函式的執行時間
簡易版本的裝飾器
直接通過傳參的方式
缺陷1:
程式碼寫死了 無法統計其他函式的執行時間
能否解決?
可以! 將函式名通過形參的形式傳入
缺陷2:
封裝成函式之後 呼叫方式改變了 不符合裝飾器原則
#程式碼示例:
import time
def get_time(func):
start_time = time.time() # 函式執行之前獲取一個時間戳
func()
end_time = time.time() # 函式執行之後獲取一個時間戳
print(end_time - start_time) # 兩個時間戳的差值就是函式的執行時間
def home():
time.sleep(3)
print('from home')
get_time(home) # from home 3.0071964263916016
'第一種直接給函式體傳參的方式無法實現裝飾器'
#程式碼示例:
import time
def index():
time.sleep(1)
print('from index')
def home():
time.sleep(3)
print('from home')
print(home)
def outer(func): # 真正的index被outer區域性名稱空間儲存了
def get_time():
start_time = time.time() # 函式執行之前獲取一個時間戳
func() # 呼叫了真正的index函式
end_time = time.time() # 函式執行之後獲取一個時間戳
print(end_time - start_time) # 兩個時間戳的差值就是函式的執行時間
return get_time
# res = outer(index) # 左側的res就是一個普通的變數名
# res()
# index = outer(index)
# index() # 看似呼叫的index其實呼叫的是get_time
# print(index) # 全域性名稱空間中的index指向的是get_time函式體程式碼
# 簡易版裝飾器
def outer(func_name): # 1. 定義外部函式
def inner(): # 3.定義內部函式
start_time = time.time() # 7. 獲取函式執行前的時間戳
func_name() # 8. 呼叫函式,內部函式呼叫外部函式繫結的形參,由於第2步形參傳值,func_name與index臨時繫結到一起,且這裡是先呼叫outer函式再賦值,所以func_name繫結的是上面的函式名index,即呼叫函式index()
end_time = time.time() # 9. 獲取函式執行後的時間戳
print(end_time - start_time) # 輸出函式執行前後時間戳的差值
return inner # 4. 把內部函式的函式名返回出去
index = outer(index) # 2. 呼叫外部函式 # 5. 定義變數名index,讓index指向outer的返回值
index() # 6. 呼叫函式,由於index指向inner,所以index()等價於inner(),即呼叫函式inner()
進階版本裝飾器
def outer(index):
def inner(*args,**kwargs): #解決引數問題
start_time = time.time()
index()
end_time =time.time()
print(end_time - start_time)
return inner
完整版本裝飾器
'解決返回值的問題'
#程式碼示例:
import time
def index():
time.sleep(1)
print('from index')
def outer(index):
def inner(*args,**kwargs):
start_time = time.time()
res=index(*args,**kwargs) #這裡執行真正的index
end_time =time.time()
print(end_time - start_time)
return #這裡返回真正index的返回值
return inner
index = outer(index)
index()
裝飾器模板
'''編寫裝飾器其實有一套固定的程式碼 不需要做任何理解'''
def outer(func_name): # func_name用於接收被裝飾的物件(函式)
def inner(*args, **kwargs):
print('執行被裝飾函式之前 可以做的額外操作')
res = func_name(*args, **kwargs) # 執行真正的被裝飾函式
print('執行被裝飾函式之後 可以做的額外操作')
return res # 返回真正函式的返回值
return inner
裝飾器的語法糖
# 讓程式碼編寫的更加好看、簡潔!!!
#無引數的語法糖
import time
def show_time(func):
def inner(): #內部引數
start_time =time.time()
func() #呼叫函式
end_time=time.time()
print('伺服器響應時間:',end_time-start_time)
return inner
@show_time #等價於func=show_time(func)
def func():
print('執行用例')
time.sleep(1)
#呼叫函式
func()
#有引數的語法糖
import time #時間模組
def have_para(name): #引數名,執行者變數
def show_time(func): #函式名呼叫變數
def inner():#內部函式,函式體
start_time =time.time()
func() #呼叫func()函式
end_time=time.time()
print('伺服器響應時間:',end_time-start_time)
print('執行者:',name)
return inner #返回inner物件
return show_time #返回show_time物件
@have_para('wendy') #等價於func=have_para('wendy')
def func():
print('執行用例')
time.sleep(1)
func()
'''
語法糖內部原理
1.使用的時候最好緊跟在被裝飾物件的上方
2.語法糖會自動將下面緊挨著的函式名傳給@後面的函式呼叫
'''
裝飾器修復技術
# 做到比真的還要真 但是本質其實沒有變
from functools import wraps
def outer(func_name):
@wraps(func_name)
def inner(*args, **kwargs):
print('執行被裝飾物件之前可以做的操作')
res = func_name(*args, **kwargs)
return res
return inner
@outer
def index():
print('from index')
@outer
def home():
'''這是home函式的註釋'''
print('from home')
help(home) # help可以檢視指定函式的註釋資訊
home()
index()