Python中裝飾器學(xué)習(xí)總結(jié)
本文研究的主要內(nèi)容是Python中裝飾器相關(guān)學(xué)習(xí)總結(jié),具體如下。
裝飾器(decorator)功能
- 引入日志
- 函數(shù)執(zhí)行時間統(tǒng)計
- 執(zhí)行函數(shù)前預(yù)備處理
- 執(zhí)行函數(shù)后清理功能
- 權(quán)限校驗等場景
- 緩存
裝飾器示例
例1:無參數(shù)的函數(shù)
from time import ctime, sleep def timefun(func): def wrappedfunc(): print("%s called at %s"%(func.__name__, ctime())) func() return wrappedfunc @timefun def foo(): print("I am foo") foo() sleep(2) foo()
分析如下:
上面代碼理解裝飾器執(zhí)行行為可理解成
foo = timefun(foo)
1,foo先作為參數(shù)賦值給func后,foo接收指向timefun返回的wrappedfunc
2,調(diào)用foo(),即等價調(diào)用wrappedfunc()
3,內(nèi)部函數(shù)wrappedfunc被引用,所以外部函數(shù)的func變量(自由變量)并沒有釋放
4,func里保存的是原foo函數(shù)對象
例2:被裝飾的函數(shù)有參數(shù)
from time import ctime, sleep def timefun(func): def wrappedfunc(a, b): print("%s called at %s"%(func.__name__, ctime())) print(a, b) func(a, b) return wrappedfunc @timefun def foo(a, b): print(a+b) foo(3,5) sleep(2) foo(2,4)
例3:被裝飾的函數(shù)有不定長參數(shù)
from time import ctime, sleep def timefun(func): def wrappedfunc(*args, **kwargs): print("%s called at %s"%(func.__name__, ctime())) func(*args, **kwargs) return wrappedfunc @timefun def foo(a, b, c): print(a+b+c) foo(3,5,7) sleep(2) foo(2,4,9)
例4:裝飾器中的return
from time import ctime, sleep def timefun(func): def wrappedfunc(): print("%s called at %s"%(func.__name__, ctime())) func() return wrappedfunc @timefun def foo(): print("I am foo") @timefun def getInfo(): return '----hahah---' foo() sleep(2) foo() print(getInfo())
執(zhí)行結(jié)果:
foo called at Sun Jun 18 00:31:53 2017
I am foo
foo called at Sun Jun 18 00:31:55 2017
I am foo
getInfo called at Sun Jun 18 00:31:55 2017
None如果修改裝飾器為return func(),則運行結(jié)果:
foo called at Sun Jun 18 00:34:12 2017
I am foo
foo called at Sun Jun 18 00:34:14 2017
I am foo
getInfo called at Sun Jun 18 00:34:14 2017
----hahah---
小結(jié):一般情況下為了讓裝飾器更通用,可以有return
例5:裝飾器帶參數(shù),在原有裝飾器的基礎(chǔ)上,設(shè)置外部變量
from time import ctime, sleep def timefun_arg(pre="hello"): def timefun(func): def wrappedfunc(): print("%s called at %s %s"%(func.__name__, ctime(), pre)) return func() return wrappedfunc return timefun @timefun_arg("itcast") def foo(): print("I am foo") @timefun_arg("python") def too(): print("I am too") foo() sleep(2) foo() too() sleep(2) too() 可以理解為 foo()==timefun_arg("itcast")(foo)()
例6:類裝飾器
裝飾器函數(shù)其實是這樣一個接口約束,它必須接受一個callable對象作為參數(shù),然后返回一個callable對象。在Python中一般callable對象都是函數(shù),但也有例外。只要某個對象重寫了 call() 方法,那么這個對象就是callable的。
class Test(): def __call__(self): print('call me!') t = Test() t() # call me 類裝飾器demo class Test(object): def __init__(self, func): print("---初始化---") print("func name is %s"%func.__name__) self.__func = func def __call__(self): print("---裝飾器中的功能---") self.__func()
說明:
1. 當(dāng)用Test來裝作裝飾器對test函數(shù)進行裝飾的時候,首先會創(chuàng)建Test的實例對象,并且會把test這個函數(shù)名當(dāng)做參數(shù)傳遞到init方法中
即在init方法中的func變量指向了test函數(shù)體
2. test函數(shù)相當(dāng)于指向了用Test創(chuàng)建出來的實例對象
3. 當(dāng)在使用test()進行調(diào)用時,就相當(dāng)于讓這個對象(),因此會調(diào)用這個對象的call方法
4. 為了能夠在call方法中調(diào)用原來test指向的函數(shù)體,所以在init方法中就需要一個實例屬性來保存這個函數(shù)體的引用
所以才有了self.func = func這句代碼,從而在調(diào)用__call方法中能夠調(diào)用到test之前的函數(shù)體
@Test def test(): print(“—-test—”) test() showpy()#如果把這句話注釋,重新運行程序,依然會看到”–初始化–”
運行結(jié)果如下:
---初始化---
func name is test
---裝飾器中的功能---
----test---
wraps函數(shù)
使用裝飾器時,有一些細節(jié)需要被注意。例如,被裝飾后的函數(shù)其實已經(jīng)是另外一個函數(shù)了(函數(shù)名等函數(shù)屬性會發(fā)生改變)。
添加后由于函數(shù)名和函數(shù)的doc發(fā)生了改變,對測試結(jié)果有一些影響,例如:
def note(func): "note function" def wrapper(): "wrapper function" print('note something') return func() return wrapper @note def test(): "test function" print('I am test') test() print(test.__doc__)
運行結(jié)果
note something
I am test
wrapper function
所以,Python的functools包中提供了一個叫wraps的裝飾器來消除這樣的副作用。例如:
import functools def note(func): "note function" @functools.wraps(func) def wrapper(): "wrapper function" print('note something') return func() return wrapper @note def test(): "test function" print('I am test') test() print(test.__doc__)
運行結(jié)果
note something
I am test
test function
總結(jié)
以上就是本文關(guān)于Python中裝飾器學(xué)習(xí)總結(jié)的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
Python?提取出SQL語句中Where的值兩種方法(示例代碼)
為了提取SQL語句中WHERE子句的值,我們可以利用Python的sqlparse庫,這是一個專門用于解析SQL語句的庫,這篇文章主要介紹了Python?提取出SQL語句中Where的值的方法,需要的朋友可以參考下2024-08-08Python數(shù)據(jù)類型轉(zhuǎn)換詳解
本篇文章里小編給大家整理的是關(guān)于Python中常用數(shù)據(jù)類型之間的轉(zhuǎn)換相關(guān)知識點,有需要的朋友們可以學(xué)習(xí)下,希望能夠給你帶來幫助2021-10-10Python Tkinter GUI編程實現(xiàn)Frame切換
本文主要介紹了Python Tkinter GUI編程實現(xiàn)Frame切換,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04通過?for?循環(huán)比較?Python?與?Ruby?的編程區(qū)別
這篇文章主要介紹了通過?for?循環(huán)比較?Python?與?Ruby?的編程區(qū)別,Ruby?與?Python?之間的差異在很大程度上可通過for循環(huán)看出本質(zhì),下文詳細介紹需要的小伙伴可以參考一下2022-05-05pandas中apply和transform方法的性能比較及區(qū)別介紹
這篇文章主要介紹了pandas中apply和transform方法的性能比較,在文中給大家講解了apply() 與transform()的相同點與不同點,需要的朋友可以參考下2018-10-10