1. 程式人生 > 程式設計 >Python如何建立裝飾器時保留函式元資訊

Python如何建立裝飾器時保留函式元資訊

問題

你寫了一個裝飾器作用在某個函式上,但是這個函式的重要的元資訊比如名字、文件字串、註解和引數簽名都丟失了。

解決方案

任何時候你定義裝飾器的時候,都應該使用 functools 庫中的 @wraps 裝飾器來註解底層包裝函式。例如:

import time
from functools import wraps
def timethis(func):
  '''
  Decorator that reports the execution time.
  '''
  @wraps(func)
  def wrapper(*args,**kwargs):
    start = time.time()
    result = func(*args,**kwargs)
    end = time.time()
    print(func.__name__,end-start)
    return result
  return wrapper

下面我們使用這個被包裝後的函式並檢查它的元資訊:

>>> @timethis
... def countdown(n):
...   '''
...   Counts down
...   '''
...   while n > 0:
...     n -= 1
...
>>> countdown(100000)
countdown 0.008917808532714844
>>> countdown.__name__
'countdown'
>>> countdown.__doc__
'\n\tCounts down\n\t'
>>> countdown.__annotations__
{'n': <class 'int'>}
>>>

討論

在編寫裝飾器的時候複製元資訊是一個非常重要的部分。如果你忘記了使用 @wraps , 那麼你會發現被裝飾函式丟失了所有有用的資訊。比如如果忽略 @wraps 後的效果是下面這樣的:

>>> countdown.__name__
'wrapper'
>>> countdown.__doc__
>>> countdown.__annotations__
{}
>>>

@wraps 有一個重要特徵是它能讓你通過屬性 __wrapped__ 直接訪問被包裝函式。例如:

>>> countdown.__wrapped__(100000)
>>>

__wrapped__ 屬性還能讓被裝飾函式正確暴露底層的引數簽名信息。例如:

>>> from inspect import signature
>>> print(signature(countdown))
(n:int)
>>>

一個很普遍的問題是怎樣讓裝飾器去直接複製原始函式的引數簽名信息, 如果想自己手動實現的話需要做大量的工作,最好就簡單的使用 @wraps 裝飾器。 通過底層的 __wrapped__ 屬性訪問到函式簽名信息。

以上就是Python如何建立裝飾器時保留函式元資訊的詳細內容,更多關於Python保留函式元資訊的資料請關注我們其它相關文章!