裝飾器類(lèi)懈凹,通用于 function 或 class method
參考: https://stackoverflow.com/questions/1288498/using-the-same-decorator-with-arguments-with-functions-and-methods
先貼上代碼恍风,后面會(huì)有一點(diǎn)解析:
import functools
import time
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
class call_logger(object):
"""
Decorator class to log calls on functions or class methods,
e.g..
@call_logger
def my_function():
class MyClass(object):
@call_logger
def my_method(self):
"""
def __init__(self, func):
self._func = func
self._wrapped = None
self._obj = None
def __call__(self, *args, **kwags):
if not self._wrapped:
if self._obj:
self._wrapped = self._wrap_method(self._func)
self._wrapped = functools.partial(self._wrapped, self._obj)
else:
self._wrapped = self._wrap_function(self._func)
return self._wrapped(*args, **kwags)
def __get__(self, obj, type=None):
self._obj = obj
return self
def _wrap_function(self, function):
"""
Perform the decorator wrapping for a regular function.
"""
@functools.wraps(function)
def inner(*args, **kwags):
"""
Implementation of the wraped function.
"""
started = time.time()
exc_name = None
result = None
try:
result = function(*args, **kwags)
except Exception as ex:
exc_name = type(ex).__name__
raise
finally:
_log_it(started, function, result, exc_name)
return result
return inner
def _wrap_method(self, method):
"""
Perform the decorator wrapping for a class method.
"""
def inner(self, *args, **kwags):
"""
Implementation of the wrapped function.
"""
started = time.time()
exc_name = None
result = None
try:
result = method(self, *args, **kwags)
except Exception as ex:
exc_name = type(ex).__name__
raise
finally:
_log_it(started, method, result, exc_name)
return inner
def _log_it(started, method, result, exc_name):
finished = time.time()
elapsed = (finished - started) * 1000
modname, methname = _get_caller_info(method)
logging.debug("%s %s takes %s ms", modname, methname, elapsed)
def _get_caller_info(method):
modname = method.__module__
methname = method.__name__
return modname, methname
@call_logger
def test():
print 'test function'
time.sleep(1)
return True
class MyClass(object):
@call_logger
def test_method(self):
time.sleep(1)
print "test method"
if __name__ == "__main__":
test()
test_obj = MyClass()
test_obj.test_method()
- 初始化時(shí)先將 目標(biāo)函數(shù)儲(chǔ)存到裝飾器實(shí)例的私有屬性 _func中,這時(shí)還沒(méi)有進(jìn)行裝飾棒旗。
2 . call 方法的調(diào)用實(shí)際完場(chǎng)了裝飾和執(zhí)行函數(shù)兩個(gè)部分。
get 方法是裝飾通用類(lèi)方法的關(guān)鍵
當(dāng)裝飾器裝飾上 test_method時(shí)皮壁,此時(shí)的test_method指向的call_logger的實(shí)例對(duì)象椭更。然后通過(guò)test_obj.test_method 時(shí)就觸發(fā)了 get方法,
傳入test_obj對(duì)象蛾魄,賦給_obj屬性虑瀑,返回call_logger自身的對(duì)象。接著()直接觸發(fā)call方法滴须,裝飾和執(zhí)行目標(biāo)方法舌狗。在_wrap_method中,注意inner函數(shù)第一個(gè)參數(shù)要傳入self扔水,因?yàn)檠b飾的是實(shí)例方法痛侍,實(shí)例方法的第一個(gè)參數(shù)為實(shí)例本身。通過(guò)偏函數(shù)來(lái)設(shè)置第一個(gè)默認(rèn)參數(shù)為self._obj