用于装饰所有方法的类的装饰器

时间:2017-10-16 15:01:41

标签: python python-decorators

我想编写类装饰器,对于所有非魔法方法,装饰这些方法。这个想法是所有类的方法在调用之后打印它的名字;我不希望装饰所有的方法,但只有类。装饰者log_method有效。我对log_class装饰器有疑问。没有错误也没有输出。

import traceback
import inspect

def log_method(func):
    def inner(*args, **kwargs):
        print("{}{}".format(int(len(traceback.extract_stack()) / 2) * " ", func.__name__))

        return func(*args, **kwargs)

    return inner

def log_class(cls):
    for m in dir(cls):
        if not m.startswith("__") and inspect.isfunction(getattr(cls, m)):
            m = log_method(m)
            print(m)
    return cls

@log_class
class Cls:
    def __init__(self):
        pass

    def A(self):
        self.B()

    def B(self):
        self.C()

    def C(self):
        pass


Cls().A()
"""
Excepted output:
A
 B
  C
"""

1 个答案:

答案 0 :(得分:3)

您应该使用setattr将方法重新绑定到类对象,并传递方法名称m;像你一样分配到本地名称m,什么都不做。

更重要的是,您目前正在将m(一个字符串)传递给log_method。相反,您应该在通过getattr

检索后传递函数对象
def log_method(func):
    def inner(*args, **kwargs):
        print("{}{}".format(int(len(traceback.extract_stack()) / 2) * " ", func.__name__))
        return func(*args, **kwargs)
    return inner

def log_class(cls):
    for m in dir(cls):
        if not m.startswith("__") and inspect.isfunction(getattr(cls, m)):
            setattr(cls, m, log_method(getattr(cls, m))) # here
    return cls
Cls.A()
#  A
#   B
#    C

PS:log_method从未用于装饰,所以它不是装饰者。