将装饰器应用于timeit的所有子类方法

时间:2016-05-18 11:14:58

标签: python-3.x python-decorators

我有一个看起来像

的方法装饰器
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应用于所有子类方法吗?

1 个答案:

答案 0 :(得分:1)

看看这个: How can I decorate all functions of a class without typing it over and over for each method added? Python

德尔南有一个很好的答案, 只将此规则添加到他的答案中

if name in getattr(cls, 'METHODS_TO_INSPECT', []):