Наследование Python - регистрация, когда поиск __mro__ находит совпадения, а когда нет
В Python предположим, что у меня есть базовая структура классов, которая выглядит следующим образом:
class Foo(object):
def do_something(self):
print 'doing a thing'
def do_another_thing(self):
print 'doing another thing'
class Bar(Foo):
def do_another_thing(self):
super(bar, self).do_another_thing()
print 'doing more stuff still'
Я понимаю как __mro__
Атрибут создан, но я хотел бы добавить ведение журнала, чтобы я мог видеть в выводе, какие методы он нашел / вызвал, когда каждый класс сделал свой вызов. Так, например, я хотел бы, чтобы это регистрировалось как прокомментировано ниже:
f = Foo()
b = Bar()
f.do_something()
#print 'Implementing foo method do_something'
b.do_something()
#print 'Did not find method do_something for bar'
#print 'Implementing foo method do_something'
f.do_another_thing()
#print 'Implementing foo method do_another_thing'
b.do_another_thing()
#print 'Implementing bar method do_another_thing'
#print 'Implementing foo method do_another_thing'
Я возился с __getattribute__
а также __get__
, но, очевидно, я недостаточно хорошо понимаю эти методы, чтобы реализовать их по желанию. Я также смотрел на использование декораторов, но я думаю, что использование дескрипторов каким-то образом, вероятно, путь для этого.
Вот что я пробовал до сих пор:
class Bar(Foo):
def do_another_thing(self):
super(Bar, self).do_another_thing()
print 'doing more stuff still'
def __getattribute__(self, key):
self_dict = object.__getattribute__(type(self), '__dict__')
if key in self_dict:
print 'Implementing {} method {}'.format(type(self).__name__, key)
v = object.__getattribute__(self, key)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
print 'Did not find method {} for {}'.format(key, type(self).__name__)
mro = object.__getattribute__(type(self), '__mro__')
for thing in mro[1:]:
v = thing.__getattribute__(self, key)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
Я также переопределил это __getattribute__
в Foo также, и мой вывод выглядит следующим образом:
Implementing Foo method do_something
doing a thing
Did not find method do_something for Bar
Did not find method do_something for Bar
doing a thing
Implementing Foo method do_another_thing
doing another thing
Implementing Bar method do_another_thing
doing another thing
doing more stuff still
Таким образом, я могу захватить правильное ведение журнала на первом уровне наследования, но не могу правильно передать вызов обратно из Bar в Foo так, чтобы я мог использовать Foo's __getattribute__
,
1 ответ
Я сделал это - похоже, это работает в моем случае использования, хотя у меня могут быть проблемы с множественным наследованием:
class loggingObject(object):
def __getattribute__(self, item):
#we let the smart __getattribute__ method of object get the object we want
v = object.__getattribute__(self, item)
#if it's not a function, then we don't care about logging where it came from
import types
if not isinstance(v, types.MethodType):
#so we finish off default implementation
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
#get the dictionary of all explicitly defined items in the class that self is an instance of
self_dict = object.__getattribute__(type(self), '__dict__')
#if item is in self_dict, then the class that self is an instance of did implement this function
if item in self_dict:
#we log, and then implement default __getattribute__ behaviour
print 'Implementing {} method {}'.format(type(self).__name__, item)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
#if we are are, item is not explicitly in self_dict, and hence the class self is an instance of did not implement this function
print 'Did not find explicit method {} for {}'.format(item, type(self).__name__)
#unbind the function from self so it can be used for comparison
actual_function = v.__func__
#get the __mro__ for the class that self is an instance of
mro = object.__getattribute__(type(self), '__mro__')
#we loop through the mro to comapre functions in each class going up the inheritance tree until we find a match
for cls in mro[1:]:
try:
#get the function for cls
function = object.__getattribute__(cls, '__dict__')[item]
#if the function from class cls and the actual_function agree, that is where we got it from
if function == actual_function:
print 'Implementing {} method {}'.format(cls.__name__, item)
break
except KeyError:
print 'Did not find explicit method {} for {}'.format(item, cls.__name__)
#now that we have logged where we got the function from, default behaviour
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
class Foo(loggingObject):
def do_something(self):
print 'doing a thing'
def do_another_thing(self):
print 'doing another thing'
class Bar(Foo):
def do_another_thing(self):
super(Bar, self).do_another_thing()
print 'doing more stuff still'