[英]In Python, is it possible to decorate both a class and non-class method with the same decorator?
我有一個簡單的異常日志記錄裝飾器,當我的腳本拋出異常時,它可以方便地發送自己的電子郵件。
def logExceptions(func):
def wrapper():
try:
func()
except Exception, e:
logger.exception(e)
return wrapper
但是,如果我想裝飾一個類方法,我必須修改wrapper()以獲取'self',否則我會收到以下錯誤:
TypeError: wrapper() takes no arguments (1 given)
當然,在那一點上我不能用它來裝飾任何非類方法,因為這樣會發生這樣的錯誤:
TypeError: wrapper() takes exactly 1 argument (0 given)
有沒有一個干凈的方法來解決這個問題? 謝謝=)
通常的做法是定義你的包裝器,使它接受*args
和**kwargs
並將它們傳遞給它包裝的函數。 這樣它就可以包裝任何函數。
另外,我得到的印象是你所謂的“類方法”是Python所謂的“實例方法”,而你所謂的“非類方法”就是Python所謂的“函數”。 Python中的“非類方法”(例如,實例方法)采用self
參數。
classmethod
和staticmethod
方法之間的區別 首先注意:靜態方法和類方法都是函數,因此標准函數規則主要適用於它們。 我理解你的問題是關於靜態方法 (沒有傳遞額外參數)和類方法 (在第一個參數中接收類)之間的區別:
class Test(object):
def standard_method(*args, **kwargs):
# it is instance method (first argument will be instance)
return args, kwargs
@classmethod
def class_method(*args, **kwargs):
# it is class method (first argument will be class)
return args, kwargs
@staticmethod
def static_method(*args, **kwargs):
# it is static method (receives only arguments passed explicitly)
return args, kwargs
證據(或者說是不言自明的例子)在這里:
>>> t = Test()
>>> t.standard_method()
((<__main__.Test object at 0x0000000002B47CC0>,), {})
>>> t.class_method()
((<class '__main__.Test'>,), {})
>>> t.static_method()
((), {})
如您所見,傳遞的參數列表根據您選擇的方法類型而有所不同。 您面臨的問題是可變數量的參數 。
有一個解決方案 - 使用參數解包:
def some_decorator(func):
def wrapper(*args, **kwargs):
# do something here
# args is a tuple with positional args, kwargs is dict with keyword args
return func(*args, **kwargs)
return wrapper
之后, some_decorator
返回的some_decorator
將接受與裝飾函數相同數量的參數。
所以這些例子都可行:
@some_decorator
def say_hello():
print 'hello'
@some_decorator
def say_something(something):
print something
為了給你完整的例子,如果你使用這樣的結構會很好(注意functools.wraps
用法):
from functools import wraps
def some_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# do something here
# args is a tuple with positional args, kwargs is dict with keyword args
return func(*args, **kwargs)
return wrapper
其原因在functools.wraps()
文檔中列出:它保留了函數名和docstring,有效地使包裝器看起來像包裝函數(有時很有用)。
裝飾的替代方法是使用sys.excepthook
,它是一個回調sys.excepthook
,對所有未捕獲的異常進行操作,您可以為其分配自定義日志記錄功能。 好處是,您不需要刪除 (更重要的是,跟蹤)您有興趣記錄異常的每個函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.