我想创建元类,它将使用跟踪装饰器来装饰每个函数 .
所以我得到了这个:
from functools import wraps
from inspect import getfile
from arrow import now
def trace(f):
@wraps(f)
def wrapper(*args, **kwargs):
print(
'{timestamp} - {file} - {function} - CALL *{args} ** {kwargs}'.format(timestamp=now().isoformat(sep=' '),
file=getfile(f),
function=f.__name__, args=args[1:],
kwargs=kwargs))
result = f(*args, **kwargs)
print(
'{timestamp} - {file} - {function} - RESULT {result}'.format(timestamp=now().isoformat(sep=' '),
file=getfile(f),
function=f.__name__,
result=result))
return result
return wrapper
class TraceLogger(type):
def __new__(mcs, name, bases, dct):
for attr in dct:
value = dct[attr]
if callable(value):
dct[attr] = trace(value)
return super(TraceLogger, mcs).__new__(mcs, name, bases, dct)
class ExampleClass(object):
__metaclass__ = TraceLogger
def foo(self):
print('foo')
@staticmethod
def bar():
print('bar')
example = ExampleClass()
example.foo()
example.bar()
跟踪适用于任何非静态函数,因为staticmethods不可调用 . 我怎样才能解开staticmethod然后在 new metclass中将它包装两次,如下所示:
dct[attr] = staticmethod(trace(value))
1 回答
(我在这个答案中链接了三个不同的问题/答案,因为我希望提供尽可能多的详细信息,而不是仅仅关闭重复 . 如果你赞成这个答案,请考虑提交相关链接的答案)
你偶然发现了一个有趣的'feature' Python,这在this问题的答案中有所解释 .
而不是
if callable(value)
你可以检查if isinstance(value, (function, staticmethod, classmethod))
但这只会导致另一个有趣的角落情况:NameError: name 'function' is not defined
(参见为什么here)(即使做import builtins ; ... ; builtins.function
也会导致错误) .你无法摆脱检查属性名称是方法,static方法还是类方法的需要,并且(在你的情况下,参见here为什么)正确的方法是使用
types.FunctionType
: