Наследование 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'
Другие вопросы по тегам