裝飾器是一個回傳函式的函式,寫一個裝飾器,除了最常見的在函式中定義函式以外,Python還允許使用類來定義一個裝飾器,
pS注意:不管你是為了Python就業還是興趣愛好,記住:專案開發經驗永遠是核心,如果你缺新專案練習或者沒有python精講教程,可以去小編的Python交流.裙 :七衣衣九七七巴而五(數字的諧音)轉換下可以找到了,里面很多新教程專案,還可以跟老司機交流討教!
1、用類寫裝飾器
下面用常見的寫法實作了一個快取裝飾器,
def cache(func):data = {}
def wrapper(*args, **kwargs):
key = f'{func.__name__}-{str(args)}-{str(kwargs)})'
if
key
in
data:
result = data.get(key)
print('cached')
else:
result = func(*args, **kwargs)
data[key] = result
print('calculated')
return
result
return wrapper
看看快取的效果,
@cachedef rectangle_area(length, width):
return length * width
rectangle_area(2, 3)
# calculated
# 6
rectangle_area(2, 3)
# cached
# 6
裝飾器的@cache是一個語法糖,相當于func = cache(func),如果這里的cache不是一個函式,而是一個類又會怎樣呢?定義一個類class Cache, 那么呼叫func = Cache(func)會得到一個物件,這時回傳的func其實是Cache的物件,定義__call__方法可以將類的實體變成可呼叫物件,可以像呼叫函式一樣呼叫物件,然后在__call__方法里呼叫原本的func函式就能實作裝飾器了,所以Cache類也能當作裝飾器使用,并且能以@Cache的形式使用,
接下來把cache函式改寫為Cache類:
class Cache:def __init__(self, func):
self.func = func
self.data = https://www.cnblogs.com/chengxuyuanaa/p/{}
def __call__(self, *args, **kwargs):
func = self.func
data = self.data
key = f'{func.__name__}-{str(args)}-{str(kwargs)})'
if
key
in
data:
result = data.get(key)
print('cached')
else:
result = func(*args, **kwargs)
data[key] = result
print('calculated')
return
result
再看看快取結果,效果一樣,
@Cachedef rectangle_area(length, width):
return length * width
rectangle_area(2, 3)
# calculated
# 6
rectangle_area(2, 3)
# cached
# 6
2、裝飾類的方法
裝飾器不止能裝飾函式,也經常用來裝飾類的方法,但是我發現用類寫的裝飾器不能直接用在裝飾類的方法上,(有點繞…)
先看看函式寫的裝飾器如何裝飾類的方法,
class Rectangle:def __init__(self, length, width):
self.length = length
self.width = width
@cache
def area(self):
return
self.length * self.width
r = Rectangle(2, 3)
r.area()
# calculated
# 6
r.area()
# cached
# 6
但是如果直接換成Cache類會報錯,這個錯誤的原因是area被裝飾后變成了類的一個屬性,而不是方法,
class Rectangle:def __init__(self, length, width):
self.length = length
self.width = width
@Cache
def area(self):
return
self.length * self.width
r = Rectangle(2, 3)
r.area()
# TypeError: area() missing 1 required positional argument: 'self'
Rectangle.area
# <__main__.Cache object at 0x0000012D8E7A6D30>
r.area
# <__main__.Cache object at 0x0000012D8E7A6D30>
回頭再來看看沒有裝飾器的情況,Python在實體化物件后把函式變成了方法,
class Rectangle:def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return
self.length * self.width
Rectangle.area
# <function Rectangle.area at 0x0000012D8E7B28C8>
r = Rectangle(2, 3)
r.area
# <bound method Rectangle.area of <__main__.Rectangle object
因此解決辦法很簡單,要用類寫的裝飾器來裝飾類的方法,只需要把可呼叫物件包裝成函式就行,
# 定義一個簡單的裝飾器,什么也不做,僅僅是把可呼叫物件包裝成函式def method(call):
def wrapper(*args, **kwargs):
return call(*args, **kwargs)
return wrapper
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
@method
@Cache
def area(self):
return
self.length * self.width
r = Rectangle(2, 3)
r.area()
# calculated
# 6
r.area()
# cached
# 6
或者用@property還能直接把方法變成屬性,
class Rectangle:def __init__(self, length, width):
self.length = length
self.width = width
@property
@Cache
def area(self):
return
self.length * self.width
r = Rectangle(2, 3)
r.area
# calculated
# 6
r.area
# cached
# 6
總結
用類寫裝飾器并非什么特別的技巧,一般情況下確實沒必要這么寫,不過這樣就可以用一些類的特性來寫裝飾器,比如類的繼承,也算是提供了另一種思路吧,
最后注意:不管你是為了Python就業還是興趣愛好,記住:專案開發經驗永遠是核心,如果你缺新專案練習或者沒有python精講教程,可以去小編的Python交流.裙 :七衣衣九七七巴而五(數字的諧音)轉換下可以找到了,里面很多新教程專案,還可以跟老司機交流討教!
本文的文字及圖片來源于網路加上自己的想法,僅供學習、交流使用,不具有任何商業用途,著作權歸原作者所有,如有問題請及時聯系我們以作處理,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/163631.html
標籤:Python
上一篇:PAT (Basic)1004 成績排名 (Python實作)
下一篇:后端開發使用pycharm的技巧
