老生常談Python進(jìn)階之裝飾器
函數(shù)也是對(duì)象
要理解Python裝飾器,首先要明白在Python中,函數(shù)也是一種對(duì)象,因此可以把定義函數(shù)時(shí)的函數(shù)名看作是函數(shù)對(duì)象的一個(gè)引用。既然是引用,因此可以將函數(shù)賦值給一個(gè)變量,也可以把函數(shù)作為一個(gè)參數(shù)傳遞或返回。同時(shí),函數(shù)體中也可以再定義函數(shù)。
裝飾器本質(zhì)
可以通過(guò)編寫(xiě)一個(gè)純函數(shù)的例子來(lái)還原裝飾器所要做的事。
def decorator(func):
def wrap():
print("Doing someting before executing func()")
func()
print("Doing someting after executing func()")
return wrap
def fun_test():
print("func")
fun_test = decorator(fun_test)
fun_test()
# Output:
# Doing someting before executing func()
# func
# Doing someting after executing func()
fun_test所指向的函數(shù)的引用傳遞給decorator()函數(shù)
decorator()函數(shù)中定義了wrap()子函數(shù),這個(gè)子函數(shù)會(huì)調(diào)用通過(guò)func引用傳遞進(jìn)來(lái)的fun_test()函數(shù),并在調(diào)用函數(shù)的前后做了一些其他的事情
decorator()函數(shù)返回內(nèi)部定義的wrap()函數(shù)引用
fun_test接收decorator()返回的函數(shù)引用,從而指向了一個(gè)新的函數(shù)對(duì)象
通過(guò)fun_test()調(diào)用新的函數(shù)執(zhí)行wrap()函數(shù)的功能,從而完成了對(duì)fun_test()函數(shù)的前后裝飾
Python中使用裝飾器
在Python中可以通過(guò)@符號(hào)來(lái)方便的使用裝飾器功能。
def decorator(func):
def wrap():
print("Doing someting before executing func()")
func()
print("Doing someting after executing func()")
return wrap
@decorator
def fun_test():
print("func")
fun_test()
# Output:
# Doing someting before executing func()
# func
# Doing someting after executing func()
裝飾的功能已經(jīng)實(shí)現(xiàn)了,但是此時(shí)執(zhí)行:
print(fun_test.__name__) # Output: # wrap
fun_test.__name__已經(jīng)變成了wrap,這是應(yīng)為wrap()函數(shù)已經(jīng)重寫(xiě)了我們函數(shù)的名字和注釋文檔。此時(shí)可以通過(guò)functools.wraps來(lái)解決這個(gè)問(wèn)題。wraps接受一個(gè)函數(shù)來(lái)進(jìn)行裝飾,并加入了復(fù)制函數(shù)名稱(chēng)、注釋文檔、參數(shù)列表等等功能。這可以讓我們?cè)谘b飾器里面訪問(wèn)在裝飾之前的函數(shù)的屬性。
更規(guī)范的寫(xiě)法:
from functools import wraps
def decorator(func):
@wraps(func)
def wrap():
print("Doing someting before executing func()")
func()
print("Doing someting after executing func()")
return wrap
@decorator
def fun_test():
print("func")
fun_test()
print(fun_test.__name__)
# Output:
# Doing someting before executing func()
# func
# Doing someting after executing func()
# fun_test
帶參數(shù)的裝飾器
通過(guò)返回一個(gè)包裹函數(shù)的函數(shù),可以模仿wraps裝飾器,構(gòu)造出一個(gè)帶參數(shù)的裝飾器。
from functools import wraps
def loginfo(info='info1'):
def loginfo_decorator(func):
@wraps(func)
def wrap_func(*args, **kwargs):
print(func.__name__ + ' was called')
print('info: %s' % info)
return func(*args, **kwargs)
return wrap_func
return loginfo_decorator
@loginfo()
def func1():
pass
func1()
# Output:
# func1 was called
# info: info1
@loginfo(info='info2')
def func2():
pass
func2()
# Output:
# func2 was called
# info: info2
裝飾器類(lèi)
通過(guò)編寫(xiě)類(lèi)的方法也可以實(shí)現(xiàn)裝飾器,并讓裝飾器具備繼承等面向?qū)ο笾懈鼘?shí)用的特性
首先編寫(xiě)一個(gè)裝飾器基類(lèi):
from functools import wraps
class loginfo:
def __init__(self, info='info1'):
self.info = info
def __call__(self, func):
@wrap
def wrap_func(*args, **kwargs):
print(func.__name__ + ' was called')
print('info: %s' % self.info)
self.after() # 調(diào)用after方法,可以在子類(lèi)中實(shí)現(xiàn)
return func(*args, **kwargs)
return wrap_func
def after(self):
pass
@loginfo(info='info2')
def func1():
pass
# Output:
# func1 was called
# info: info1
再通過(guò)繼承l(wèi)oginfo類(lèi),擴(kuò)展裝飾器的功能:
class loginfo_after(loginfo):
def __init__(self, info2='info2', *args, **kwargs):
self.info2 = info2
super(loginfo_after, self).__init__(*args, **kwargs)
def after(self):
print('after: %s' % self.info2)
@loginfo_after()
def func2():
pass
func2()
# Output:
# func2 was called
# info: info1
# after: info2
以上這篇老生常談Python進(jìn)階之裝飾器就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于Django signals 信號(hào)作用及用法詳解
這篇文章主要介紹了基于Django signals 信號(hào)作用及用法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
學(xué)會(huì)用Python實(shí)現(xiàn)滑雪小游戲,再也不用去北海道啦
Python除了極少的事情不能做之外,其他基本上可以說(shuō)全能.,圖形處理、文本處理、數(shù)據(jù)庫(kù)編程、網(wǎng)絡(luò)編程、web編程、黑客編程、爬蟲(chóng)編寫(xiě)、機(jī)器學(xué)習(xí)、人工智能等.接下來(lái)我就教大家做一個(gè)不用去北海道也可以滑雪的小游戲,需要的朋友可以參考下2021-05-05
使用python將時(shí)間轉(zhuǎn)換為指定的格式方法
今天小編就為大家分享一篇使用python將時(shí)間轉(zhuǎn)換為指定的格式方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-11-11
Django Admin實(shí)現(xiàn)上傳圖片校驗(yàn)功能
這篇文章主要介紹了Django Admin實(shí)現(xiàn)上傳圖片校驗(yàn)功能的相關(guān)資料,需要的朋友可以參考下2016-03-03
python中os.stat().st_size、os.path.getsize()獲取文件大小
本文介紹了使用os.stat()和os.path.getsize()函數(shù)獲取文件大小,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01

