首页 文章

“解开”并在元类中再次包装@staticmethod

提问于
浏览
1

我想创建元类,它将使用跟踪装饰器来装饰每个函数 .

所以我得到了这个:

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 回答

  • 0

    (我在这个答案中链接了三个不同的问题/答案,因为我希望提供尽可能多的详细信息,而不是仅仅关闭重复 . 如果你赞成这个答案,请考虑提交相关链接的答案)

    你偶然发现了一个有趣的'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

    import types
    
    ...
    
    if type(value) == types.FunctionType: # or isinstance(value, types.FunctionType)
        dct[attr] = trace(value)
    
    ...
    

相关问题