一、裝飾器的定義:通俗地說,就是裝飾其他函式,為其他函式新增附加功能,本質上也是函式。
但要遵循兩個原則:
1.不能修改被裝飾函式的源**
2.不能修改被裝飾函式的呼叫方式
簡言之,裝飾器對被裝飾函式是完全透明的。
二、在實現裝飾器之前,我們還要先弄明白以下3個知識點:
1.函式即「變數」:在python中,無論是變數還是函式,在定義後,python都會在記憶體中為其分配乙個位址,用來存放變數或函式的內容,在呼叫該變數或函式時,只要能在記憶體中找到變數或函式的記憶體位址,就可以正常執行。
舉例來說,
def
foo():
print('in the foo')
bar()
foo() # 如果在此刻呼叫函式foo,就會報錯,因為函式bar還沒有定義,記憶體中找不到其內容
defbar
(): print('in the bar')
foo() # 而在此刻呼叫函式foo,就可以正常執行,因為呼叫前,函式bar已正常定義及分配記憶體位址
2.高階函式
1) 把乙個函式名做為實參傳遞給另乙個函式
(實現在不修改被裝飾函式源**的情況下為其新增附加功能)
舉例說明,
import time
defdeco
(func):
start_time = time.time()
func()
stop_time = time.time()
deftest1
(): time.sleep(3)
print('in the test1')
deco(test1) # 在不修改test1源**的情況下,實現了計算函式test1的執行時間
2) 返回值中包含函式名
(實現了不修改被裝飾函式的呼叫方式)
import time
deffoo
(func):
print(func) # 列印的是函式func的記憶體位址
return func
defbar
(): time.sleep(3)
print('in the bar')
bar = foo(bar)
bar() # 顯然,呼叫方式沒有被改變
3.巢狀函式:在乙個函式裡再定義另乙個函式
def
gradpa
(): x=1
defdad
(): x=2
defson
(): x=3
print(x)
son()
dad()
gradpa()
輸出結果:3
注意:巢狀函式必須是在函式裡再定義另乙個函式,而高階函式是呼叫另乙個函式
三、裝飾器的實現:高階函式+巢狀函式
被裝飾函式沒有引數
import time
# 裝飾器timer
deftimer
(func):
defdeco
(): start_time = time.time()
func()
stop_time = time.time()
print('the function run time is %s' %(stop_time - start_time))
return deco
@timer # 在python裡,用@+裝飾器函式名,放在被裝飾函式上面,實際等同於test1 = timer(test1)
deftest1
(): time.sleep(3)
print('in the test1')
# test1 = timer(test1) # 結果為deco
test1() #等同於deco()
2.被裝飾函式有0-n個引數
*args:不固定位置引數
**kwargs:關鍵字引數
import time
# 裝飾器timer
deftimer
(func):
# 加入*args, **kwargs,無論被裝飾函式擁有幾個引數,都可以正常執行
defdeco
(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
stop_time = time.time()
print('the function run time is %s' %(stop_time - start_time))
return deco
@timer
deftest2
(name):
time.sleep(3)
print('in the test2',name)
# test2 = timer(test2) # 結果為deco
test2('amy') #等同於deco('amy')
3.被裝飾函式有返回值
import time
# 裝飾器timer
deftimer
(func):
defdeco
(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs) # 將函式func的返回值賦給res
stop_time = time.time()
print('the function run time is %s' %(stop_time - start_time))
return res # 返回res,就可以將被裝飾函式的返回值輸出
return deco
@timer
deftest3
(name):
time.sleep(3)
print('in the test3',name)
return
'hello test3'
# test3 = timer(test3) # 結果為deco
test3('amy') #等同於deco('amy')
4.根據條件給被裝飾函式裝飾不同功能
舉例說明:假設有三個頁面,index首頁無需登入就能訪問,home和bbs頁面需要輸入正確使用者名稱密碼才能進入,且home用本地認證,bbs用遠端ldap驗證
user = 'amy'
passwd = 'abc123'
# 使用者登入認證裝飾器
defauth
(auth_type):
# 第一層,傳入不同的驗證方式auth_type,返回函式loggin
defloggin
(func):
# 第二層,傳入被裝飾函式func,返回函式deco
defdeco
(*args, **kwargs):
if auth_type == 'local':
username = input('username:').strip()
password = input('password:').strip()
if username == user and password == passwd:
res = func(*args, **kwargs)
return res
else:
exit('invalid username or password!')
elif auth_type == 'ldap':
print('sorry, i don\'t konw ldap')
return deco
return loggin
defindex
(): print('welcome to index page')
@auth(auth_type='local') # 執行結果等同於home = deco()
defhome
(): print('welcome to home page')
@auth(auth_type='ldap')
defbbs
(): print('welcome to bbs page')
index()
home()
bbs()
裝飾器語法糖
什麼是裝飾器語法糖 toc裝飾器語法糖屬於裝飾器的 注意 在使用裝飾器語法糖時,裝飾器必須定義在被裝飾物件之上 import time 統計函式執行時間裝飾器 def inner args,kwargs 被裝飾物件的引數 呼叫前增加新功能 start time time.time 呼叫被裝飾物件,並...
Python語法糖 裝飾器
這裡用來記錄python各種甜得發膩的語法糖,以及各種變形用法。太初,神諭 pythonic import light,於是有了光。裝飾器是用來給函式增加新功能的,對於支援高階函式的語言,函式引數直接穿進去就好了。但是python提供了更為優雅的解決方案,只需要乙個 就能搞定。裝飾器函式需要單獨寫出...
Python語法糖 裝飾器
這裡用來記錄python各種甜得發膩的語法糖,以及各種變形用法。太初,神諭 pythonic import light,於是有了光。裝飾器是用來給函式增加新功能的,對於支援高階函式的語言,函式引數直接穿進去就好了。但是python提供了更為優雅的解決方案,只需要乙個 就能搞定。裝飾器函式需要單獨寫出...