python三大器之裝飾器詳解
裝飾器
講裝飾器之前要先了解兩個概念:
- 對象引用 :對象名僅僅只是個綁定內(nèi)存地址的變量
def func():# 函數(shù)名僅僅只是個綁定內(nèi)存地址的變量 print("i`m running") # 這是調(diào)用 func() # i`m running # 這是對象引用,引用的是內(nèi)存地址 func2 = func print(func2 is func) # True # 通過引用進(jìn)行調(diào)用 func2() # i`m running
- 閉包:定義一個函數(shù)A,然后在該函數(shù)內(nèi)部再定義一個函數(shù)B,并且B函數(shù)用到了外邊A函數(shù)的變量
def out_func(): out_a = 10 def inner_func(inner_x): return out_a + inner_x return inner_func out = out_func() print(out) # <function out_func.<locals>.inner_func at 0x7ff378af5c10> out_func返回的是inner_func的內(nèi)存地址 print(out(inner_x=2)) # 12
裝飾器和閉包不同點在于:裝飾器的入?yún)⑹?strong>函數(shù)對象,閉包入?yún)⑹瞧胀〝?shù)據(jù)對象
def decorator_get_function_name(func): """ 獲取正在運行函數(shù)名 :return: """ def wrapper(*arg): """ wrapper :param arg: :return: """ print(f"當(dāng)前運行方法名:{func.__name__} with params: {arg}") return func(*arg) return wrapper @decorator_get_function_name def test_func_add(x, y): print(x + y) @decorator_get_function_name def test_func_sub(x, y): print(x - y) test_func_add(1, 2) # 當(dāng)前運行方法名:test_func_add with params: (1, 2) # 3 test_func_sub(3, 5) # 當(dāng)前運行方法名:test_func_sub with params: (3, 5) # -2
常用于如鑒權(quán)校驗,例如筆者會用于登陸校驗:
def login_check(func): def wrapper(request, *args, **kwargs): if not request.session.get('login_status'): return HttpResponseRedirect('/api/login/') return func(request, *args, **kwargs) return wrapper @login_check def edit_config(): pass
裝飾器內(nèi)部的執(zhí)行邏輯:
""" > 1. def login_check(func): ==>將login_check函數(shù)加載到內(nèi)存 > .... > @login_check ==>此處已經(jīng)在內(nèi)存中將login_check這個函數(shù)執(zhí)行了!;并不需要等edit_config()實例化調(diào)用 > 2. 上例@login_check內(nèi)部會執(zhí)行以下操作: > 2.1 執(zhí)行l(wèi)ogin_check函數(shù),并將 @login_check 下面的 函數(shù)(edit_config) 作為login_check函數(shù)的參數(shù),即:@login_check 等價于 login_check(edit_config) > 2.2 內(nèi)部就會去執(zhí)行: def wrapper(*args): # 校驗session... return func(request, *args, **kwargs)# func是參數(shù),此時 func 等于 edit_config,此處相當(dāng)于edit_config(request, *args, **kwargs) return wrapper # 返回的 wrapper,wrapper代表的是函數(shù)對象,非函數(shù)實例化對象 2.3 其實就是將原來的 edit_config 函數(shù)塞進(jìn)另外一個函數(shù)中,另一個函數(shù)當(dāng)中可以做一些操作;再執(zhí)行edit_config 2.4 將執(zhí)行完的 login_check 函數(shù)返回值(也就是 wrapper對象)將此返回值再重新賦值給新 edit_config,即: 2.5 新edit_config = def wrapper: # 校驗session... return 原來edit_config(request, *args, **kwargs) > 3. 也就是新edit_config()=login_check(edit_config):wrapper(request, *args, **kwargs):return edit_config(request, *args, **kwargs) 有點繞,大家看步驟細(xì)細(xì)理解。 """
同樣一個函數(shù)也可以使用多個裝飾器進(jìn)行裝飾,執(zhí)行順序從上到下
from functools import wraps def w1(func): @wraps(func) def wrapper(*args, **kwargs): print("這里是第一個校驗") return func(*args, **kwargs) return wrapper def w2(func): @wraps(func) def wrapper(*args, **kwargs): print("這里是第二個校驗") return func(*args, **kwargs) return wrapper def w3(func): def wrapper(*args, **kwargs): print("這里是第三個校驗") return func(*args, **kwargs) return wrapper @w2 # 這里其實是w2(w1(f1)) @w1 # 這里是w1(f1) def f1(): print(f"i`m f1, at {f1}") @w3 def f2(): print(f"i`m f2, at {f2}") # ====================== 實例化階段 ===================== f1() # 這里是第二個校驗 # 這里是第一個校驗 # i`m f1, at <function f1 at 0x7febc52f5e50> f2() # 這里是第三個校驗 # i`m f2, at <function w3.<lo
有同學(xué)可能要好奇 為什么f1對象打印的是“<function f1 at 0x7febc52f5e50>”,f2對象打印的是“<function w3..wrapper at 0x7febc52f5f70>”(也就是步驟2.5造成的,賦的值是wrapper對象),這就跟w1和w2 內(nèi)部wrapper使用的wraps裝飾器有關(guān)系了。
wraps的作用是:被修飾的函數(shù)(也就是里面的func)的一些屬性值賦值給修飾器函數(shù)(wrapper)包括元信息和“函數(shù)對象”等。
同時裝飾器也可以接受參數(shù):
def decorator_get_function_duration(enable): """ :param enable: 是否需要統(tǒng)計函數(shù)執(zhí)行耗時 :return: """ print("this is decorator_get_function_duration") def inner(func): print('this is inner in decorator_get_function_duration') @wraps(func) def wrapper(*args, **kwargs): print('this is a wrapper in decorator_get_function_duration.inner') if enable: start = time.time() print(f"函數(shù)執(zhí)行前:{start}") result = func(*args, **kwargs) print('[%s]`s enable was %s it`s duration : %.3f s ' % (func.__name__, enable, time.time() - start)) else: result = func(*args, **kwargs) return result return wrapper return inner def decorator_1(func): print('this is decorator_1') @wraps(func) def wrapper(*args, **kwargs): print('this is a wrapper in decorator_1') return func(*args, **kwargs) return wrapper def decorator_2(func): print('this is decorator_2') @wraps(func) def wrapper(*args, **kwargs): print('this is a wrapper in decorator_2') return func(*args, **kwargs) return wrapper @decorator_1 # 此處相當(dāng):decorator_1(decorator_2(decorator_get_function_duration(enable=True)(fun))) @decorator_2 # = decorator_2(decorator_get_function_duration(enable=True)(fun)) @decorator_get_function_duration(enable=True) # = decorator_get_function_duration(enable=True)(fun) def fun(): time.sleep(2) print("fun 執(zhí)行完了~") fun() # ======== enable=False ============ """ this is decorator_get_function_duration this is inner in decorator_get_function_duration this is decorator_2 this is decorator_1 this is a wrapper in decorator_1 this is a wrapper in decorator_2 this is a wrapper in decorator_get_function_duration.inner fun 執(zhí)行完了~ """ # ======== enable=True ============ """ this is decorator_get_function_duration this is inner in decorator_get_function_duration this is decorator_2 this is decorator_1 this is a wrapper in decorator_1 this is a wrapper in decorator_2 this is a wrapper in decorator_get_function_duration.inner 函數(shù)執(zhí)行前:1634635708.648994 fun 執(zhí)行完了~ [fun]`s enable was True it`s duration : 2.002 s """
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注本站的更多內(nèi)容!
版權(quán)聲明:本站文章來源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場,如有內(nèi)容涉嫌侵權(quán),請聯(lián)系alex-e#qq.com處理。