пример о С3 - PullRequest
       26

пример о С3

0 голосов
/ 19 февраля 2019

Я получил следующий код от github о MRO и C3, и я не совсем понимаю последние три строки и в чем разница между super (). Foo (), super (B, self) .foo () и super (C, self) .foo () в python3.x, код следующий:

class A(object):

    def foo(self):
        print('foo of A')

class B(A):
    pass

class C(A):

    def foo(self):
        print('foo fo C')

class D(B, C):
    pass

class E(D):

    def foo(self):
        print('foo in E')
        super().foo()
        super(B, self).foo()
        super(C, self).foo()

if __name__ == '__main__':
    d = D()
    d.foo()
    e = E()
    e.foo()

ожидаемые и фактические результаты следующие:

foo fo C
foo in E
foo fo C
foo fo C
foo of A    

1 Ответ

0 голосов
/ 19 февраля 2019

Прежде всего, форма super() в Python 3 - это то же самое, что и super(<CurrentClass>, self), где компилятор Python предоставляет достаточно информации для super(), чтобы определить, какой правильный класс использовать .Таким образом, в E.foo(), super().foo() можно прочитать как super(E, self).foo().

Чтобы понять, что происходит, вам нужно взглянуть на атрибут class.__mro__ :

Этот атрибут является кортежем классов, которые учитываются при поиске базовых классов во время разрешения метода.

Именно этот кортеж показывает, что такое C3 Порядок разрешения метода для любой данной иерархии классов.Для вашего класса E этот порядок:

>>> E.__mro__
(<class '__main__.E'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
>>> for cls in E.__mro__:  # print out just the names, for easier readability.
...     print(cls.__name__)
...
E
D
B
C
A
object

Объект super() основывает все на этой упорядоченной последовательности классов.Вызов

super(SomeClass, self).foo()

приводит к следующей последовательности шагов:

  • Объект super() извлекает кортеж self.__mro__.
  • super() locatesиндекс для класса SomeClass в этом кортеже.
  • Доступ к атрибуту foo объекта super() запускает поиск класса с атрибутом foo в MRO, начиная со следующего индекса после SomeClass index .
  • Если атрибут, найденный таким образом, является объектом дескриптора , связывает атрибут, найденный таким образом, с self.Функции являются дескрипторами, привязка создает связанный метод, и именно так Python передает ссылку self при вызове метода.

Выражается в виде упрощенного кода Python, который игнорирует крайние случаи и другое использование дляsuper(), это будет выглядеть так:

class Super:
    def __init__(self, type_, obj_or_type):
        self.mro = obj_or_type.__mro__
        self.idx = self.mro.index(type_) + 1
        self.obj_or_type = obj_or_type
    def __getattr__(self, name):
        for cls in self.mro[self.idx:]:
            attrs = vars(cls)
            if name in attrs:
                result = attrs[name]
                if hasattr(result, '__get__'):
                    result = result.__get__(obj_or_type, type(self.obj_or_type))
                return result
        raise AttributeError(name)

Комбинируя эти два фрагмента информации, вы можете увидеть, что происходит, когда вы звоните e.foo():

  • print('foo in E') isвыполняется, в результате чего foo в E
  • super().foo() выполняется, то же самое, что и super(E, self).foo().
    • MRO ищется, начиная со следующего индекса мимо E, поэтому с D (без атрибута foo), переходя к B (без * 1079)* атрибут), затем C (атрибут найден).C.foo возвращается, привязанный к self.
    • C.foo(self) вызывается, в результате чего foo fo C
  • super(B, self).foo()выполнен.
    • Поиск MRO начинается со следующего индекса мимо B, т. Е. С C (атрибут найден).C.foo возвращается, привязанный к self.
    • C.foo(self) вызывается, в результате чего foo fo C
  • super(C, self).foo()выполнен.
    • Поиск MRO начинается со следующего индекса после C, т. Е. С A (атрибут найден).A.foo возвращается, связанный с self.
    • A.foo(self) вызывается, в результате foo A
...