我想创建将用跟踪装饰器装饰每个函数的元类。
所以我明白了:
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()
跟踪适用于任何非静态函数,因为静态方法不可调用。 我如何解开静态方法,然后在 new metclass中将其包装两次,如下所示:
dct[attr] = staticmethod(trace(value))
答案 0 :(得分:1)
您可以通过对其调用 staticmethod
来解包 __get__
对象。
@staticmethod
def func(*args):
print('func called:', args)
return 42
print(func)
print(func.__get__(None, object))
print(func.__get__(None, object)(1, 2, 3))
它输出:
<staticmethod object at 0x7f8d42835ac0>
<function func at 0x7f8d429561f0>
func called: (1, 2, 3)
42
至于为什么会这样,您可能有兴趣了解描述符协议是什么,我推荐this link。
答案 1 :(得分:0)
(我在此答案中链接了三个不同的问题/答案,因为我想提供尽可能多的详细信息,而不是重复多次。如果您对此答案表示赞同,请考虑对链接的答案也进行投票)
您偶然发现了Python的一个有趣的“功能”,该问题在this问题的答案中得到了解释。
您可以检查if callable(value)
而不是if isinstance(value, (function, staticmethod, classmethod))
,但这只会导致另一个有趣的极端情况:NameError: name 'function' is not defined
(请参阅here的原因)(即使这样做{{ 1}}会导致错误)。
您无法摆脱检查属性名称是方法,静态方法还是类方法的麻烦,而(可能会看到here的正确方法)是使用import builtins ; ... ; builtins.function
:
types.FunctionType