內(nèi)置語(yǔ)法糖 格式優(yōu)美 逼格較高
成都創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿(mǎn)足客戶(hù)于互聯(lián)網(wǎng)時(shí)代的鹿寨網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
在代碼中使用洽到好處的裝飾器瞬間讓代碼優(yōu)美很多
寫(xiě)起來(lái)也很簡(jiǎn)單 無(wú)參的裝飾器參數(shù)是要裝飾的函數(shù) 有參裝飾器參數(shù)是需要的參數(shù) 最后返回的是內(nèi)部函數(shù)!
裝飾器是通過(guò)裝飾器函數(shù)修改原函數(shù)的一些功能而不需要修改原函數(shù),在很多場(chǎng)景可以用到它,比如① 執(zhí)行某個(gè)測(cè)試用例之前,判斷是否需要登錄或者執(zhí)行某些特定操作;② 統(tǒng)計(jì)某個(gè)函數(shù)的執(zhí)行時(shí)間;③ 判斷輸入合法性等。合理使用裝飾器可以極大地提高程序的可讀性以及運(yùn)行效率。本文將介紹Python裝飾器的使用方法。
python裝飾器可以定義如下:
輸出:
python解釋器將test_decorator函數(shù)作為參數(shù)傳遞給my_decorator函數(shù),并指向了內(nèi)部函數(shù) wrapper(),內(nèi)部函數(shù) wrapper() 又會(huì)調(diào)用原函數(shù) test_decorator(),所以decorator()的執(zhí)行會(huì)先打印'this is wrapper',然后打印'hello world', test_decorator()執(zhí)行完成后,打印 'bye' ,*args和**kwargs,表示接受任意數(shù)量和類(lèi)型的參數(shù)。
裝飾器 my_decorator() 把真正需要執(zhí)行的函數(shù) test_decorator() 包裹在其中,并且改變了它的行為,但是原函數(shù) test_decorator() 不變。
一般使用如下形式使用裝飾器:
@my_decorator就相當(dāng)于 decorator = my_decorator(test_decorator) 語(yǔ)句。
內(nèi)置裝飾器@functools.wrap可用于保留原函數(shù)的元信息(將原函數(shù)的元信息,拷貝到對(duì)應(yīng)的裝飾器函數(shù)里)。先來(lái)看看沒(méi)有使用functools的情況:
輸出:
從上面的輸出可以看出test_decorator() 函數(shù)被裝飾以后元信息被wrapper() 函數(shù)取代了,可以使用@functools.wrap裝飾器保留原函數(shù)的元信息:
輸出:
裝飾器可以接受自定義參數(shù)。比如定義一個(gè)參數(shù)來(lái)設(shè)置裝飾器內(nèi)部函數(shù)的執(zhí)行次數(shù):
輸出:
Python 支持多個(gè)裝飾器嵌套:
裝飾的過(guò)程:
順序從里到外:
test_decorator('hello world') 執(zhí)行順序和裝飾的過(guò)程相反。
輸出:
類(lèi)也可以作為裝飾器,類(lèi)裝飾器主要依賴(lài)__call__()方法,是python中所有能被調(diào)用的對(duì)象具有的內(nèi)置方法(python魔術(shù)方法),每當(dāng)調(diào)用一個(gè)類(lèi)的實(shí)例時(shí),__call__()就會(huì)被執(zhí)行一次。
下面的類(lèi)裝飾器實(shí)現(xiàn)統(tǒng)計(jì)函數(shù)執(zhí)行次數(shù):
輸出:
下面介紹兩種裝飾器使用場(chǎng)景
統(tǒng)計(jì)函數(shù)執(zhí)行所花費(fèi)的時(shí)間
輸出:
在使用某些web服務(wù)時(shí),需要先判斷用戶(hù)是否登錄,如果沒(méi)有登錄就跳轉(zhuǎn)到登錄頁(yè)面或者提示用戶(hù)登錄:
--THE END--
可以的,
裝飾器分為可帶參數(shù)和不可帶參數(shù)的兩種;但是如果帶參數(shù),則帶參數(shù)裝飾器的“參數(shù)”及“return”必須也是一個(gè)裝飾器
具體可以參考一下下面的例子:
def?deco1(func):
def?w(x,*args,**kw):
print?"this?is?deco1"
return?x?+?"?decorator"
return?w
def?deco2(deco):
print?"this?is?deco2"
return?deco
@deco2(deco1)
def?func(x):
return?x
print?func("Hello")
裝飾器(decorator)是Python中的高級(jí)語(yǔ)法。裝飾的意思就是動(dòng)態(tài)擴(kuò)展被裝飾對(duì)象的功能。裝飾器可以用于裝飾函數(shù)、方法和類(lèi)。
一 嵌套函數(shù)
# 定義一個(gè)外層函數(shù)def foo(): # 定義了一個(gè)內(nèi)部函數(shù) def bar(): print("hello world")
函數(shù)bar是一個(gè)定義在foo函數(shù)內(nèi)部的函數(shù)。
Python中的函數(shù)是支持嵌套的,也就是可以在一個(gè)函數(shù)內(nèi)部再定義一個(gè)函數(shù)。
然后,我們還知道函數(shù)是可以當(dāng)作變量的,于是我們就可以在foo函數(shù)中把定義的這個(gè)bar函數(shù)返回。就像下面這樣:
# 定義一個(gè)外層函數(shù)def foo(): # 定義了一個(gè)內(nèi)層函數(shù) def bar(): print("hello world") return
barfunc = foo()func() # func -- bar,這里執(zhí)行func其實(shí)就相當(dāng)于執(zhí)行了在foo函數(shù)內(nèi)部定義的bar函數(shù)
二 閉包形態(tài)1
# 閉包形態(tài)1def foo(): name = "Andy" # 外部函數(shù)的局部變量 # 定義了一個(gè)內(nèi)部函數(shù) def bar():
print(name) # 雖然bar函數(shù)中沒(méi)有定義name變量,但是它可以訪問(wèn)外部函數(shù)的局部變量name return barfunc =
foo()func() # func -- bar -- 除了是一個(gè)函數(shù),還包含一個(gè)值(它外層函數(shù)的局部變量)的引用
三 閉包形態(tài)2
# 閉包形態(tài)2def foo(name): # 給一個(gè)函數(shù)傳參也相當(dāng)于給函數(shù)定義了一個(gè)局部變量 # 定義了一個(gè)內(nèi)部函數(shù) def bar():
print(name) # 內(nèi)部函數(shù)同樣可以獲取到傳到外部函數(shù)的變量(參數(shù)) return barfunc = foo("Andy") #
把“Andy”當(dāng)成參數(shù)傳入foo函數(shù) -- 其內(nèi)部定義的bar函數(shù)也能拿到這個(gè)“Andy”func() # func -- bar --
除了是一個(gè)函數(shù),還包含一個(gè)值(它外層函數(shù)的參數(shù))的引用
四 裝飾器形態(tài)1
# 還是定義一個(gè)外層函數(shù)def foo(name): # 我接收的參數(shù)是一個(gè)函數(shù)名 # 定義了一個(gè)內(nèi)部函數(shù) def bar():
print("這是新功能。。。") # 新功能 name() # 函數(shù)名加()就相當(dāng)于執(zhí)行-- 我傳進(jìn)來(lái)原函數(shù)的函數(shù)名,這里就相當(dāng)于執(zhí)行了原函數(shù)
return bar# 定義一個(gè)被裝飾的函數(shù)def f1(): print("hello world.") # 用foo函數(shù)裝飾f1函數(shù)f1 =
foo(f1)# 不改變f1的調(diào)用方式f1() # -- 此時(shí)函數(shù)已經(jīng)擴(kuò)展了新功能
五 裝飾器形態(tài)2
# 還是定義一個(gè)外層函數(shù)def foo(name): # 接收的參數(shù)是一個(gè)函數(shù)名 # 定義了一個(gè)內(nèi)部函數(shù) def bar():
print("這是新功能。。。") # 新功能 name() # 函數(shù)名加()就相當(dāng)于執(zhí)行-- 傳進(jìn)來(lái)原函數(shù)的函數(shù)名,這里就相當(dāng)于執(zhí)行了原函數(shù)
return bar# 定義一個(gè)被裝飾的函數(shù)# 用foo函數(shù)裝飾f1函數(shù)@foo # 使用f1 =
foo(f1)語(yǔ)法裝飾的話稍顯啰嗦,Python就提供了@語(yǔ)法,讓裝飾過(guò)程更簡(jiǎn)便def f1(): print("hello world.") #
不改變f1的調(diào)用方式f1() # -- 此時(shí)函數(shù)已經(jīng)擴(kuò)展了新功能。
首先十分不推薦這種做法, 會(huì)令程序難以維護(hù).
其次, 多個(gè)裝飾器是按照裝飾器的順序進(jìn)行執(zhí)行的.
如果你編寫(xiě)過(guò)裝飾器, 你就應(yīng)該知道, 其實(shí)裝飾器就是把函數(shù)的名字傳入進(jìn)去, 在執(zhí)行函數(shù)之前, 進(jìn)行一些提前的處理.
例如下面這段代碼, 自定義的裝飾器
def add_schedid(handler_func):
"""
@handler_func: 請(qǐng)求處理函數(shù)
"""
@functools.wraps(handler_func)
def wrapper(self, *args, **kwargs):
"""
wrapper
"""
# handler_func就是所裝飾的函數(shù),可以在這里做一些真正函數(shù)執(zhí)行前所需的處理,
handler_func(self, *args, **kwargs)
return wrapper
裝飾器本身就是一個(gè)函數(shù), 將所裝飾的函數(shù), 作為一個(gè)參數(shù)傳進(jìn)來(lái), 然后在執(zhí)行這個(gè)函數(shù)之前, 進(jìn)行一個(gè)處理,這就是裝飾器. 所以和正常函數(shù)執(zhí)行順序是一樣的..
1. 函數(shù)帶多個(gè)參數(shù)
# 普通的裝飾器, 打印函數(shù)的運(yùn)行時(shí)間
def decrator(func):
def wrap(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print('運(yùn)行時(shí)間為', end_time-start_time)
return res
return wrap
2. 裝飾器帶有多個(gè)參數(shù)
當(dāng)裝飾器帶有多個(gè)參數(shù)的時(shí)候, 裝飾器函數(shù)就需要多加一層嵌套:
比如:
def decrator(*dargs, **dkargs):
def wrapper(func):
def _wrapper(*args, **kargs):
print ("裝飾器參數(shù):", dargs, dkargs)
print ("函數(shù)參數(shù):", args, kargs)
return func(*args, **kargs)
return _wrapper
return wrapper
為什么被裝飾函數(shù)體可以傳入內(nèi)層呢?
裝飾器函數(shù)有多個(gè)參數(shù), 需要以
@decrator(1, a=2)
的方式使用, 這時(shí)候decrator是已經(jīng)執(zhí)行的(因?yàn)榧恿死ㄌ?hào)), 可以粗略的理解為加載被裝飾函數(shù)的上的是wrapper, 所以這和普通的裝飾器并無(wú)差別.
又如flask源碼中的:
def route(self, rule, **options):
"""Like :meth:`Flask.route` but for a blueprint. The endpoint for the
:func:`url_for` function is prefixed with the name of the blueprint.
"""
def decorator(f):
endpoint = options.pop("endpoint", f.__name__)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
flask的藍(lán)圖route源碼中的裝飾器, 最內(nèi)層直接返回return f 并沒(méi)有多加一層處理的函數(shù), 在無(wú)需對(duì)被裝飾函數(shù)進(jìn)行過(guò)多處理的時(shí)候這是較為方便的做法. route源碼中只是對(duì)裝飾器參數(shù)進(jìn)行了處理.