2017-10-16 194 views
1

我想写所有非魔法方法的类修饰器来装饰这些方法。这个想法是,所有类的方法在打电话后打印它的名字;我不想装饰所有的方法,但只有阶级。装饰者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

'm = log_method(m)'只是给变量'm'赋值'log_method'的返回值,它根本不影响类。 –

回答

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从不用于装饰,所以它不是一个装饰。

+1

不错。现在用元类来做。 ;) –

+0

@ PM2Ring抛出一个元类,并且答案变成一个漩涡,如果OP没有以前的经验,那么更有可能是这样:) –