Python: Logging all of a class' methods without decorating each one
我想记录一些类中的每个方法调用。我本来可以的
1 2 3 4 5 6 7 | class Class1(object): @log def method1(self, *args): ... @log def method2(self, *args): ... |
但是我在每节课上都有很多方法,我不想单独装饰每一个。目前,我尝试对元类使用hack(重写我记录的类'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class LoggedMeta(type): def __new__(cls, name, bases, attrs): def __getattribute__(self, name_): attr = super().__getattribute__(name_) if isinstance(attr, (types.MethodType, types.FunctionType)) and not name_.startswith("__"): return makeLogged(attr) #This returns a method that first logs the method call, and then calls the original method. return attr attrs["__getattribute__"] = __getattribute__ return type.__new__(cls, name, bases, attrs) class Class1(object): __metaclass__ = LoggedMeta def method1(self, *args): ... |
但是,我在python2.x上,super()语法不起作用。在我调用super的时候,我没有
我之前试过使用元类,但是重写了所有的方法而不是
我搜索了这类问题,但没有发现有人试图用这种方式改变课堂。
任何想法或帮助都将非常感谢。
编辑:我的解决方案是(大部分取自此线程):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | import inspect, types CLASS = 0 NORMAL = 1 STATIC = 2 class DecoratedMethod(object): def __init__(self, func, type_): self.func = func self.type = type_ def __get__(self, obj, cls=None): def wrapper(*args, **kwargs): print"before" if self.type == CLASS: #classmethods (unlike normal methods) reach this stage as bound methods, but args still contains the class #as a first argument, so we omit it. ret = self.func(*(args[1:]), **kwargs) else: ret = self.func(*args, **kwargs) print"after" return ret for attr in"__module__","__name__","__doc__": setattr(wrapper, attr, getattr(self.func, attr)) if self.type == CLASS: return types.MethodType(wrapper, cls, type) elif self.type == NORMAL: return types.MethodType(wrapper, obj, cls) else: return wrapper def decorate_class(cls): for name, meth in inspect.getmembers(cls): if inspect.ismethod(meth): if inspect.isclass(meth.im_self): # meth is a classmethod setattr(cls, name, DecoratedMethod(meth, CLASS)) else: # meth is a regular method setattr(cls, name, DecoratedMethod(meth, NORMAL)) elif inspect.isfunction(meth): # meth is a staticmethod setattr(cls, name, DecoratedMethod(meth, STATIC)) return cls @decorate_class class MyClass(object): def __init__(self): self.a = 10 print"__init__" def foo(self): print self.a @staticmethod def baz(): print"baz" @classmethod def bar(cls): print"bar" |
后来我清理了一下,但这就是解决方案的本质。我需要类、静态方法和普通方法之间的区别,因为我希望
1 2 3 4 | inst = MyClass() assert type(inst.baz) == types.FunctionType assert type(inst.foo) == types.MethodType assert type(inst.bar) == types.MethodType |
为什么不更改类对象?
您可以使用
1 2 3 4 5 | def logify(klass): for member in dir(klass): if not callable(getattr(klass, method)) continue # skip attributes setattr(klass, method, log(method)) |
胡乱摆弄这样的东西…应该工作…
一个班级装饰师可以在这里帮忙。修饰整个类,并将日志记录功能添加到类具有的所有可调用属性中。
我建议从这篇文章中选择所有方法修饰器,那么您的代码将是
1 2 3 4 | @for_all_methods(log) class Class1(): def method1(self): pass ... |