我希望在某些类中调用时记录调试信息。记录的数据是:
我希望包装器非常通用。同时,包装应在运行时进行。我创建了以下包装类,它记录信息并将调用委托给原始实例。
import datetime
import traceback
from functools import partial
from logging_module import db_log
class BaseWrapper(object):
def __init__(self, item):
self._item = item
def __getattr__(self, attr):
return getattr(self._item, attr)
class DBLogWrapper(BaseWrapper):
@staticmethod
def _time_method(method):
name = "{0}.{1}.{2}".format(
method.im_class.__module__,
method.im_class.__name__,
method.__name__
)
def timed_method(self, *args, **kwargs):
begin = datetime.datetime.now()
return_val = method.im_func(self, *args, **kwargs)
end = datetime.datetime.now()
trace = traceback.format_stack()
db_log(
name,
begin,
end,
info={
'args': args,
'kwargs': kwargs,
'trace': trace
}
)
return return_val
return timed_method
def __init__(self, item, methods):
super(DBLogWrapper, self).__init__(item)
for method in methods:
class_method = getattr(item, method)
wrapped_method = DBLogWrapper._time_method(class_method)
wrapped_method = partial(wrapped_method, self._item)
setattr(self, method, wrapped_method)
示例用法:
class MyClass(object):
def hello(self, greeting):
print greeting
def goodbye(self):
print 'Good Bye'
a = MyClass()
if DEBUG:
a = DBLogWrapper(a, ['hello'])
a.hello()
a.goodbye()
在这种情况下,将记录对hello
的调用,但不会调用goodbye
。
然而,对于一项似乎应该简单的任务而言,这似乎有些过分。我正在寻找有关如何改进上述代码的建议或完全不同的方法。
答案 0 :(得分:3)
你做得太多了。您根本不需要partial
。只需在没有timed_method
参数的情况下定义self
,然后直接调用method
:
import datetime
import traceback
from functools import partial
def db_log(*args, **kwargs): print args, kwargs # Mock
class BaseWrapper(object):
def __init__(self, instance):
self._instance = instance
def __getattr__(self, attr):
return getattr(self._instance, attr)
class DBLogWrapper(BaseWrapper):
@staticmethod
def _time_method(method):
name = "{0}.{1}.{2}".format(
method.im_class.__module__,
method.im_class.__name__,
method.__name__
)
def timed_method(*args, **kwargs):
begin = datetime.datetime.now()
return_val = method(*args, **kwargs)
end = datetime.datetime.now()
trace = traceback.format_stack()
db_log(
name,
begin,
end,
info={
'args': args,
'kwargs': kwargs,
'trace': trace
}
)
return return_val
return timed_method
def __init__(self, instance, methods):
super(DBLogWrapper, self).__init__(instance)
for method in methods:
class_method = getattr(instance, method)
wrapped_method = DBLogWrapper._time_method(class_method)
setattr(self, method, wrapped_method)
输出:
>>> a = MyClass()
>>> a = prova.DBLogWrapper(a, ['hello'])
>>> a.hello()
A
('__main__.MyClass.hello', datetime.datetime(2013, 1, 17, 20, 48, 26, 478023), datetime.datetime(2013, 1, 17, 20, 48, 26, 478071)) {'info': {'args': (), 'trace': [' File "<stdin>", line 1, in <module>\n', ' File "prova.py", line 31, in timed_method\n trace = traceback.format_stack()\n'], 'kwargs': {}}}
>>> a.goodbye()
B
无论如何,你可能会使用一些__getattr__
魔法,例如:
class DBLogWrapper2(BaseWrapper):
def __init__(self, instance, methods):
super(DBLogWrapper, self).__init__(instance)
self._methods = methods
def __getattr__(self, attr):
if attr not in methods:
return getattr(self._instance, attr)
def f(*args, **kwargs):
return self.timed_method(getattr(self._item, attr),
*args, **kwargs)
return f
def timed_method(method, *args, **kwargs):
begin = datetime.datetime.now()
return_val = method(*args, **kwargs)
end = datetime.datetime.now()
trace = traceback.format_stack()
db_log(name,
begin,
end,
info={
'args': args,
'kwargs': kwargs,
'trace': trace
}
)
return return_val