裝飾器(Decorators)


定義
裝飾器是一個函數,它可以將另一個函數作為參數,並在不永久修改該函數的情況下擴展或改變其行為。裝飾器提供了一種靈活的方法來為函數或方法添加功能。

用途
裝飾器常用於日誌記錄、訪問控制、快取(memoization)等功能。它們可以應用於任何函數,並且通常以一種簡潔且可讀的方式增強功能。

 

以下舉例一個簡單的例子:simple_decorator(func),func指的是想要裝飾的function,下面的例子是say_hello function,在simple_decorator額外定義wrapper function是python定義的使用方式,名稱不一定要教wrapper。wrapper內的功能可以自由定義,比如下面的例子就是,在執行say_hello前因為前面識別到@simple_decorator,所以變成執行裝飾器(Decorator),而執行內容則是wrapper函數,可以看到會先print "Before function execution" -> say_hello -> print "Afterfunction execution"

def simple_decorator(func):
  def wrapper():
    print("Before function execution.")
    func()
    print("After function execution")
 return wrapper
# must place at a function which you want to decorate
@simple_decorator
def say_hello():
  print("Hello!")
say_hello()

 

執行結果則會如下所示,可以看到@simple_decorator用在裝飾say_hello function。

Before function execution.
Hello!
After function execution

 

 

經過簡單的介紹,可以了解到裝飾器(Decorator)對於function的可擴充性非常大,由於我們不需要更改原本函數即可位原本函數增加功能,這對於大型專案非常有利。以下會再多做幾的簡單的裝飾器用法。

  • 計算函數執行時間: 我們可以用裝飾器來讓原本函數得到計算時間的功能,方法如下
def time_decorator(func):
  def wrapper():
    start_time = time.time()
    result = func()
    end_time = time.time()
    print(f"Function execution time: {end_time - start_time}")
    return result 
  return wrapper
 
 
@time_decorator
def exec_func():
  time.sleep(2)
  print("Function finished!")

 

  • 驗證參數: 下面的例子是,可以驗證傳入參數是否為正數square_root(-1),帶入-1,這時顯示結果會變成ValueError: The number must be positive
def validate_positive(func):
  def wrapper(x):
    if x <= 0:
      raise ValueError("The number must be positive")
    return func(x)
 return wrapper
 
 
@validate_positive
def square_root(x):
  return x**0.5
print(square_root(-1))
  • 裝飾器帶參數: 若是裝飾器想要帶入參數,可以用以下作法,這時需要一個裝飾器工廠 (Decorator Factory)來接受參數,通常是用來動態配置裝飾器使用本身並非裝飾器。下面這個例子,角色分別為, conditional_decorator = 裝飾器工廠, decorator = 裝飾器, wrapper = 包裝函數。常見用法就是可以控制函數本身能不能被啟動,比如should_run = False表示表示我不想啟動greet()這個function。因此最後執行結果為Function will not run
def conditional_decorator(should_run=True):
  def decorator(func):
    def wrapper(*args, **kwargs):
      if should_run:
        return func(*args, **kwargs)
      else:
        print("Function will not run")
   return wrapper
 return decorator
 
 
@conditional_decorator(should_run=False)
def greet():
  print("Hello!")
greet()

 

  • 多個裝飾器:  這個例子展示了如何使用多個裝飾器來裝飾一個函數,並且每個裝飾器會依序執行,由上至下依序執行裝飾器。decorator_one -> decorator_two
def decorator_one(func):
  def wrapper():
    print("Decorator One")
    func()
 return wrapper
 
 
def decorator_two(func):
  def wrapper():
    print("Decorator Two")
    func()
 return wrapper
 
 
@decorator_one
@decorator_two
def greet():
  print("Hello")
greet()
  • 裝飾器實現快取(cache):  這個裝飾器用來cached函數的結果,這樣如果相同的參數再次調用,則直接返回cached的結果,而不再執行函數。因為我們創建了cache字典,來cache住結果,在wrapper函數中,我們直接查找cache dictionary,如果有存在裡面的話會直接返回cache值。實際上我目前還沒碰過比較大型的專案,所以這類用法還沒有很熟悉,不過看起來應該使用起來好處滿多的。
def cache_decorator(func):
   cache = {}
  def wrapper(x):
    if x in cache:
      return cache[x]
    result = func(x)
    cache[x] = result
    return result
  return wrapper
@cache_decorator
def expensive_compute(x):
  print(f"Compute {x}...")
  return x * x
print(expensive_compute(4))
print(expensive_compute(4))

 

以上就是裝飾器(Decorator),自己研究加上一些網路資料所的知的用法,如果有更多的使用方式歡迎留言告訴我

 

文章標籤
全站熱搜
創作者介紹
創作者 Luke 的頭像
Luke

Luke的部落格

Luke 發表在 痞客邦 留言(0) 人氣(12)