我有一个看起来像
的方法装饰器def debug_run(fn):
from functools import wraps
@wraps(fn)
def wrapper(self, *args, **kw):
# log some stuff
# timeit fn
res = fn(self, *args, **kw)
return wrapper
现在我习惯使用它来应用我要调试的每个方法。现在我正在尝试使用类装饰器来应用所有类方法。
宁愿做
class A():
@debug_run
def f(self):
pass
我做
@decallmethods(debug_run)
class A():
def f(self):
pass
def decallmethods(decorator):
def dectheclass(cls):
for name, m in inspect.getmembers(cls, inspect.ismethod):
if name in getattr(cls, 'METHODS_TO_INSPECT', []):
setattr(cls, name, decorator(m))
return cls
return dectheclass
尝试将decorator应用于基类,而不是按预期工作。没有登录到控制台。现在我想知道这种方法是好还是我应该使用别的东西(将调试装饰器应用于从基类到所有子类的选定方法)。
[编辑]
终于找到了为什么没有打印日志
Why is there a difference between inspect.ismethod and inspect.isfunction from python 2 -> 3?
这是一个反映我的代码的完整示例
import inspect
import time
import logging as logger
from functools import wraps
logger.basicConfig(format='LOGGER - %(asctime)s %(message)s', level=logger.DEBUG)
def debug_run(fn):
@wraps(fn)
def wrapper(self, *args, **kw):
logger.debug(
"call method %s of instance %s with %r and %s "
% (fn.__name__, self, args, kw))
time1 = time.time()
res = fn(self, *args, **kw)
time2 = time.time()
logger.debug(
"%s function %0.3f ms" % (fn, (time2-time1)*1000.0))
return res
return wrapper
def decallmethods(decorator):
def dectheclass(cls):
for name, m in inspect.getmembers(
cls, predicate=lambda x: inspect.isfunction(x) or inspect.ismethod(x)):
methods_to_inspect = getattr(cls, 'METHODS_TO_INSPECT', [])
if name in methods_to_inspect:
setattr(cls, name, decorator(m))
return cls
return dectheclass
class B(object):
METHODS_TO_INSPECT = ["bfoo1", "bfoo2", "foo"]
def __str__(self):
return "%s:%s" % (repr(self), id(self))
def bfoo1(self):
pass
def bfoo2(self):
pass
def foo(self):
pass
def run(self):
print("print - Base run doing nothing")
class C(object):
pass
@decallmethods(debug_run)
class A(B, C):
METHODS_TO_INSPECT = ["bfoo1", "bfoo2", "foo", "run"]
def foo(self):
print("print - A foo")
def run(self):
self.bfoo1()
self.bfoo2()
self.foo()
a = A()
b = B()
a.run()
b.run()
在这种情况下,将decallmethods应用于B,不会影响A所以我必须同时应用于A和B两个B的所有子类。
有可能有这样的机制允许将decallmethods应用于所有子类方法吗?
答案 0 :(得分:1)
if name in getattr(cls, 'METHODS_TO_INSPECT', []):