python三大器之裝飾器詳解
裝飾器
講裝飾器之前要先了解兩個(gè)概念:
- 對(duì)象引用 :對(duì)象名僅僅只是個(gè)綁定內(nèi)存地址的變量
def func(): # 函數(shù)名僅僅只是個(gè)綁定內(nèi)存地址的變量
print("i`m running")
# 這是調(diào)用
func() # i`m running
# 這是對(duì)象引用,引用的是內(nèi)存地址
func2 = func
print(func2 is func) # True
# 通過(guò)引用進(jìn)行調(diào)用
func2() # i`m running
- 閉包:定義一個(gè)函數(shù)A,然后在該函數(shù)內(nèi)部再定義一個(gè)函數(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
裝飾器和閉包不同點(diǎn)在于:裝飾器的入?yún)⑹?strong>函數(shù)對(duì)象,閉包入?yún)⑹瞧胀〝?shù)據(jù)對(duì)象
def decorator_get_function_name(func):
"""
獲取正在運(yùn)行函數(shù)名
:return:
"""
def wrapper(*arg):
"""
wrapper
:param arg:
:return:
"""
print(f"當(dāng)前運(yùn)行方法名:{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)前運(yùn)行方法名:test_func_add with params: (1, 2)
# 3
test_func_sub(3, 5)
# 當(dāng)前運(yùn)行方法名:test_func_sub with params: (3, 5)
# -2
常用于如鑒權(quán)校驗(yàn),例如筆者會(huì)用于登陸校驗(yà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這個(gè)函數(shù)執(zhí)行了?。徊⒉恍枰萫dit_config()實(shí)例化調(diào)用
> 2. 上例@login_check內(nèi)部會(huì)執(zhí)行以下操作:
> 2.1 執(zhí)行l(wèi)ogin_check函數(shù),并將 @login_check 下面的 函數(shù)(edit_config) 作為login_check函數(shù)的參數(shù),即:@login_check 等價(jià)于 login_check(edit_config)
> 2.2 內(nèi)部就會(huì)去執(zhí)行:
def wrapper(*args):
# 校驗(yàn)session...
return func(request, *args, **kwargs) # func是參數(shù),此時(shí) func 等于 edit_config,此處相當(dāng)于edit_config(request, *args, **kwargs)
return wrapper # 返回的 wrapper,wrapper代表的是函數(shù)對(duì)象,非函數(shù)實(shí)例化對(duì)象
2.3 其實(shí)就是將原來(lái)的 edit_config 函數(shù)塞進(jìn)另外一個(gè)函數(shù)中,另一個(gè)函數(shù)當(dāng)中可以做一些操作;再執(zhí)行edit_config
2.4 將執(zhí)行完的 login_check 函數(shù)返回值(也就是 wrapper對(duì)象)將此返回值再重新賦值給新 edit_config,即:
2.5 新edit_config = def wrapper:
# 校驗(yàn)session...
return 原來(lái)edit_config(request, *args, **kwargs)
> 3. 也就是新edit_config()=login_check(edit_config):wrapper(request, *args, **kwargs):return edit_config(request, *args, **kwargs) 有點(diǎn)繞,大家看步驟細(xì)細(xì)理解。
"""
同樣一個(gè)函數(shù)也可以使用多個(gè)裝飾器進(jìn)行裝飾,執(zhí)行順序從上到下
from functools import wraps
def w1(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("這里是第一個(gè)校驗(yàn)")
return func(*args, **kwargs)
return wrapper
def w2(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("這里是第二個(gè)校驗(yàn)")
return func(*args, **kwargs)
return wrapper
def w3(func):
def wrapper(*args, **kwargs):
print("這里是第三個(gè)校驗(yàn)")
return func(*args, **kwargs)
return wrapper
@w2 # 這里其實(shí)是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}")
# ====================== 實(shí)例化階段 =====================
f1()
# 這里是第二個(gè)校驗(yàn)
# 這里是第一個(gè)校驗(yàn)
# i`m f1, at <function f1 at 0x7febc52f5e50>
f2()
# 這里是第三個(gè)校驗(yàn)
# i`m f2, at <function w3.<lo
有同學(xué)可能要好奇 為什么f1對(duì)象打印的是“<function f1 at 0x7febc52f5e50>”,f2對(duì)象打印的是“<function w3..wrapper at 0x7febc52f5f70>”(也就是步驟2.5造成的,賦的值是wrapper對(duì)象),這就跟w1和w2 內(nèi)部wrapper使用的wraps裝飾器有關(guān)系了。
wraps的作用是:被修飾的函數(shù)(也就是里面的func)的一些屬性值賦值給修飾器函數(shù)(wrapper)包括元信息和“函數(shù)對(duì)象”等。
同時(shí)裝飾器也可以接受參數(shù):
def decorator_get_function_duration(enable):
"""
:param enable: 是否需要統(tǒng)計(jì)函數(shù)執(zhí)行耗時(shí)
: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é)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Python3中最常用的5種線程鎖實(shí)例總結(jié)
python3線程中鎖機(jī)制還是很重要的知識(shí)點(diǎn),如果大家不清楚鎖機(jī)制的話,那就一定要好好看下這篇文章,這篇文章主要給大家總結(jié)介紹了光宇Python3中最常用的5種線程鎖,需要的朋友可以參考下2021-07-07
Python用 KNN 進(jìn)行驗(yàn)證碼識(shí)別的實(shí)現(xiàn)方法
這篇文章主要介紹了Python用 KNN 進(jìn)行驗(yàn)證碼識(shí)別的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-02-02
Protocol Buffers(Protobuf)功能及使用方法
本文介紹了ProtocolBuffers(Protobuf)及其編譯器protoc,包括其數(shù)據(jù)描述語(yǔ)言的特性、編譯器的功能、.proto文件的定義、使用方法、支持的編程語(yǔ)言、安裝步驟、常用命令選項(xiàng)以及高級(jí)功能,感興趣的朋友跟隨小編一起看看吧2025-01-01
詳解Python如何利用pymysql封裝項(xiàng)目通用的連接和查詢
一個(gè)項(xiàng)目通常都需要有數(shù)據(jù)庫(kù),本文就來(lái)為大家詳細(xì)講講Python如何利用pymysql簡(jiǎn)單分裝一個(gè)通用的連接,關(guān)閉和查詢,需要的可以參考一下2022-07-07
Python通過(guò)paramiko遠(yuǎn)程下載Linux服務(wù)器上的文件實(shí)例
今天小編就為大家分享一篇Python通過(guò)paramiko遠(yuǎn)程下載Linux服務(wù)器上的文件實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
Python安裝模塊的常見(jiàn)問(wèn)題及解決方法
下面小編就為大家分享一篇Python安裝模塊的常見(jiàn)問(wèn)題及解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02

