Я хочу регистрировать каждый вызов метода в некоторых классах. Я мог бы сделатьPython: протоколирование всех методов класса без оформления каждого из них
class Class1(object):
@log
def method1(self, *args):
...
@log
def method2(self, *args):
...
Но у меня есть много методов в каждом классе, и я не хочу, чтобы украсить каждую из них в отдельности. В настоящее время я пытался использовать хак с метаклассами (переопределение моего класса вошли __getattribute__
так, что если я пытаюсь получить метод, он будет возвращать метод протоколирования вместо):
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):
...
Однако, я на Python 2.X, а синтаксис super() не работает. В то время, когда я называю супер, у меня нет класса __getattribute__
(но у меня есть его имя класса), поэтому я не могу использовать старый синтаксис super(Class, Inst)
.
Я попытался использовать метаклассы раньше, но переопределить все методы вместо __getattribute__
, но я хочу также регистрировать статические вызовы методов, и они дали мне некоторые проблемы.
Я искал этот вопрос, но не нашел никого, кто пытался изменить класс таким образом.
Любые идеи или помощь будут очень благодарны.
EDIT: Мое решение было это (в основном взяты из this нити):
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"
позже я очистил его немного, но это суть раствора. Мне нужна эта разница между классными, статическими и обычными методами, потому что я хочу иметь
inst = MyClass()
assert type(inst.baz) == types.FunctionType
assert type(inst.foo) == types.MethodType
assert type(inst.bar) == types.MethodType
Возможный дубликат [Как я могу украсить все функции класса, не вводя его снова и снова для каждого добавленного метода? Python] (http://stackoverflow.com/questions/6307761/how-can-i-decorate-all-functions-of-a-class-without-typing-it-over-and-over-for) – Flynsee