亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python中怎么利用類實現一個裝飾器

發布時間:2021-06-16 16:11:14 來源:億速云 閱讀:210 作者:Leah 欄目:開發技術

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

看看緩存的效果。

@cache
def 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 = {}
  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

再看看緩存結果,效果一樣。

@Cache
def 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

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宝兴县| 利辛县| 永善县| 长岛县| 武鸣县| 泰和县| 萨嘎县| 开鲁县| 陆河县| 八宿县| 石楼县| 灌南县| 麻阳| 东至县| 合江县| 曲靖市| 普安县| 淳化县| 湘西| 阿拉善盟| 长治县| 游戏| 大庆市| 湟源县| 宁明县| 尚义县| 济宁市| 咸宁市| 兴化市| 久治县| 德清县| 白朗县| 兖州市| 庆阳市| 延津县| 武胜县| 崇信县| 同江市| 广东省| 咸阳市| 都兰县|