關於 Python 裝飾器的一些個人理解

dustinny發表於2021-03-05

  裝飾器

  本質是一個接受引數為函式的函式。

  作用:為一個已經實現的方法新增額外的通用功能,比如日誌記錄、執行計時等。

  舉例

  不帶引數的裝飾器,不用@

  # 不帶引數的裝飾器

  def deco_test(func):

  def wrapper(*args, **kwargs):

  print("before function")

  f = func(*args, **kwargs)

  print("after function")

  return f

  return wrapper

  def do_something(a,b,c):

  print(a)

  time.sleep(1)

  print(b)

  time.sleep(1)

  print(c)

  return a

  if __name__ == '__main__':

  # 不用@

  f = deco_test(do_something)("1","2","3")

  輸出:

  before function

  1

  2

  3

  after function

  個人理解:

  相當於在 do_something 函式外面套了兩個輸出:before function 和 after function。

  不帶引數的裝飾器,用 @

  # 不帶引數的裝飾器

  def deco_test(func):

  def wrapper(*args, **kwargs):

  print("before function")

  f = func(*args, **kwargs)

  print("after function")

  return f

  return wrapper

  @deco_test

  def do_something(a,b,c):

  print(a)

  time.sleep(1)

  print(b)

  time.sleep(1)

  print(c)

  return a

  if __name__ == '__main__':

  # 使用@

  f = do_something("1","2","3")

  輸出:

  before function

  1

  2

  3

  after function

  個人理解:

  相當於執行 do_something 函式的時候,因為有 @ 的原因,已經知道有一層裝飾器 deco_test,所以不需要再單獨寫 deco_test(do_something) 了。

  帶引數的裝飾器

  # 帶引數的裝飾器

  def logging(level):

  def wrapper(func):

  def inner_wrapper(*args, **kwargs):

  print("[{level}]: enter function {func}()".format(level=level, func=func.__name__))

  f = func(*args, **kwargs)

  print("after function: [{level}]: enter function {func}()".format(level=level, func=func.__name__))

  return f

  return inner_wrapper

  return wrapper

  @logging(level="debug")

  def do_something(a,b,c):

  print(a)

  time.sleep(1)

  print(b)

  time.sleep(1)

  print(c)

  return a

  if __name__ == '__main__':

  # 使用@

  f = do_something("1","2","3")

  輸出:

  [debug]: enter function do_something()

  1

  2

  3

  after function: [debug]: enter function do_something()

  個人理解:

  裝飾器帶了一個引數 level = "debug"。

  最外層的函式 logging() 接受引數並將它們作用在內部的裝飾器函式上面。內層的函式 wrapper() 接受一個函式作為引數,然後在函式上面放置一個裝飾器。這裡的關鍵點是裝飾器是可以使用傳遞給 logging() 的引數的。

  類裝飾器

  # 類裝飾器

  class deco_cls(object):

  def __init__(self, func):

  self._func = func

  def __call__(self, *args, **kwargs):

  print("class decorator before function")

  f = self._func(*args, **kwargs)

  print("class decorator after function")

  return f

  @deco_cls

  def do_something(a,b,c):

  print(a)

  time.sleep(1)

  print(b)

  time.sleep(1)

  print(c)

  return a

  if __name__ == '__main__':

  # 使用@

  f = do_something("1","2","3")

  輸出:

  class decorator before function

  1

  2

  3

  class decorator after function

  個人理解:

  使用一個裝飾器去包裝函式,返回一個可呼叫的例項。 因此定義了一個類裝飾器。

  兩層裝飾器

  # 不帶引數的裝飾器

  def deco_test(func):

  def wrapper(*args, **kwargs):

  print("before function")

  f = func(*args, **kwargs)

  print("after function")

  return f

  return wrapper

  # 帶引數的裝飾器

  def logging(level):

  def wrapper(func):

  def inner_wrapper(*args, **kwargs):

  print("[{level}]: enter function {func}()".format(level=level, func=func.__name__))

  f = func(*args, **kwargs)

  print("after function: [{level}]: enter function {func}()".format(level=level, func=func.__name__))

  return f

  return inner_wrapper

  return wrapper

  @logging(level="debug")

  @deco_test

  def do_something(a,b,c):

  print(a)

  time.sleep(1)

  print(b)

  time.sleep(1)

  print(c)

  return a

  if __name__ == '__main__':

  # 使用@

  f = do_something("1","2","3")

  輸出:

  [debug]: enter function wrapper()

  before function

  1

  2

  3

  after function

  after function: [debug]: enter function wrapper()

  個人理解:

  在函式 do_something() 外面先套一層 deco_test() 裝飾器,再在最外面套一層 logging() 裝飾器。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69995861/viewspace-2761341/,如需轉載,請註明出處,否則將追究法律責任。

相關文章