什麼是裝飾器
裝飾器本身是一個函數 ,作用是爲現有存在的函數,在不改變函數的基礎上去增加一些功能進行裝飾,裝飾器是通過閉包的形式實現的。
我另一篇博客:☞閉包的實現原理,如何在內部函數修改外部函數的變量
函數萬能裝飾器
這個裝飾器只是一種形式,沒有實際意義。
# 定義萬能函數裝飾器
def outFunc(func):
# 接收不同的參數
def wrapper(*args, **kwargs):
print('萬能裝飾器')
# 再原樣傳回給被裝飾的函數
return func(*args, **kwargs)
return wrapper
# 進行裝飾
@outFunc
def addNmu(a,b):
return a+b
# 調用被裝飾的addNum函數
print(addNmu(3,4))
# 執行效果
# 萬能裝飾器
# 7
類裝飾器
實現方法:在類中通過使用 __init__和 __call__方法來實現,__init__接收要被裝飾的函數,__call__實現具體的裝飾內容。
類裝飾器也是用來裝飾函數的。
一切都在代碼中:
class Test(object):
# 通過初始化方法,將要被裝飾的函數傳進來並記錄下來
def __init__(self, func):
self.__func = func
# 重寫 __call__ 方法來實現具體裝飾內容
def __call__(self, *args, **kwargs):
print('類的裝飾器實現')
self.__func(*args, **kwargs)
def show():
print('i am func show')
# 裝飾前,show是一個函數
show()
# 裝飾後,show變成了Test類的實例對象
test1 = Test(show)
test1()
#------------------------------------------------------
# 執行效果
# 裝飾前
# i am func show
# 裝飾後
# 類的裝飾器實現
# i am func show
有沒有注意到__call__方法
__call__方法:Python中,只要在創建類的時候定義了__call__方法,這個類就是可調用的。
什麼意思呢?通過幾段代碼來看:
class Call(object):
n = 1
# 實例化對象
test2 = Call()
print(test2.n)
# 結果
# 1
思考,我們能不能像調用函數一樣使用類對象呢?
class Call(object):
n = 1
test2 = Call()
print(test2())
運行結果:
錯誤提示,Call不能被調用;加入call方法:
class Call(object):
def __call__(self, *args, **kwargs):
n = 1
return n
test2 = Call()
print(test2())
# 運行結果
# 1
結論
是不是感覺有點多此一舉?我們在這裏是爲了理解__call__方法的作用:
- Python中的所有東西都是對象,其中包括Int/str/func/class這四類,它們都是對象,都是從一個類創建而來的。
- 爲了將一個類實例當做函數調用,我們需要在類中實現__call__()方法。
- 最重要的一點,前面類裝飾器的實現就是藉助__call__方法實現的。
補充
__new__方法:實例化對象(開闢內存空間)
__init__方法:對實例化對象進行初始化操作
__call__方法:讓類可調用,實現裝飾器
__str__方法:當使用print輸出對象的時候,默認打印對象的內存地址。如果類定義了__str__方法,那麼就會打印從在這個方法中return的數據
__del__方法:當刪除對象時,python解釋器會默認調用這個方法,讓這個對象的引用計數減1,當對象的引用計數爲0的時候,則對象纔會被真正刪除(內存被回收)。