Как Python super () работает с множественным наследованием?

Как утверждали другие, у вас нет гарантии относительно порядка, когда вы перебираете свойства объекта. Если вам нужен упорядоченный список нескольких полей, я предложил создать массив объектов.

var myarr = [{somfield1: 'x', somefield2: 'y'},
{somfield1: 'a', somefield2: 'b'},
{somfield1: 'i', somefield2: 'j'}];

Таким образом вы можете использовать регулярный цикл и иметь порядок вставки. Затем вы можете использовать метод сортировки массива, чтобы отсортировать его в новом массиве, если это необходимо.

771
задан Peter O. 29 July 2014 в 20:39
поделиться

3 ответа

Это подробно описано с разумным количеством деталей самим Гвидо в его сообщении в блоге Порядок разрешения методов (включая две более ранние попытки).

В вашем примере Third () вызовет First .__ init __ . Python ищет каждый атрибут в родительских классах, поскольку они перечислены слева направо. В этом случае мы ищем __ init __ . Итак, если вы определите

class Third(First, Second):
    ...

Python начнет с рассмотрения First , и, если First не имеет атрибута, тогда он будет смотреть на Second ].

Эта ситуация усложняется, когда наследование начинает пересекать пути (например, если Первый унаследован от Второй ). Прочтите ссылку выше для получения более подробной информации, но, вкратце, Python будет пытаться поддерживать порядок, в котором каждый класс появляется в списке наследования, начиная с самого дочернего класса.

Так, например, если у вас есть:

class First(object):
    def __init__(self):
        print "first"

class Second(First):
    def __init__(self):
        print "second"

class Third(First):
    def __init__(self):
        print "third"

class Fourth(Second, Third):
    def __init__(self):
        super(Fourth, self).__init__()
        print "that's it"

MRO будет [Четвертый, Второй, Третий, Первый].

Между прочим: если Python не может найти согласованный порядок разрешения методов, он вызовет исключение вместо того, чтобы вернуться к поведению, которое может удивить пользователя.

Отредактировано, чтобы добавить пример неоднозначного MRO:

class First(object):
    def __init__(self):
        print "first"

class Second(First):
    def __init__(self):
        print "second"

class Third(First, Second):
    def __init__(self):
        print "third"

Должен Третья MRO быть [Первый, Второй] или [Второй, Первый] ]? Нет очевидных ожиданий, и Python выдаст ошибку:

TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution order (MRO) for bases Second, First

Edit: Я вижу, как несколько человек утверждают, что в приведенных выше примерах отсутствуют вызовы super () , поэтому позвольте мне объяснить: Примеры должны показать, как строится ТОиР. Они не предназначены для печати «первая \ nсекунда \ третья» или что-то еще. Вы можете - и, конечно же, должны поэкспериментировать с примером, добавить вызовы super () , посмотреть, что происходит, и получить более глубокое понимание модели наследования Python. Но моя цель здесь - упростить и показать, как строится ТОиР. И он построен, как я объяснил:

>>> Fourth.__mro__
(<class '__main__.Fourth'>,
 <class '__main__.Second'>, <class '__main__.Third'>,
 <class '__main__.First'>,
 <type 'object'>)
659
ответ дан 22 November 2019 в 21:14
поделиться

В python 3.5 + наследование выглядит предсказуемым и очень хорошим для меня. Смотрит на этот код:

class Base(object):
  def foo(self):
    print("    Base(): entering")
    print("    Base(): exiting")


class First(Base):
  def foo(self):
    print("   First(): entering Will call Second now")
    super().foo()
    print("   First(): exiting")


class Second(Base):
  def foo(self):
    print("  Second(): entering")
    super().foo()
    print("  Second(): exiting")


class Third(First, Second):
  def foo(self):
    print(" Third(): entering")
    super().foo()
    print(" Third(): exiting")


class Fourth(Third):
  def foo(self):
    print("Fourth(): entering")
    super().foo()
    print("Fourth(): exiting")

Fourth().foo()
print(Fourth.__mro__)

Выводы:

Fourth(): entering
 Third(): entering
   First(): entering Will call Second now
  Second(): entering
    Base(): entering
    Base(): exiting
  Second(): exiting
   First(): exiting
 Third(): exiting
Fourth(): exiting
(<class '__main__.Fourth'>, <class '__main__.Third'>, <class '__main__.First'>, <class '__main__.Second'>, <class '__main__.Base'>, <class 'object'>)

, Как Вы видите, это называет нечто точно ОДНИМ временем для каждой наследованной цепочки в том же порядке, как это было наследовано. Можно получить тот порядок путем вызова . mro:

Четвертый-> Треть-> Сначала-> Второй-> Основа-> объект

1
ответ дан 22 November 2019 в 21:14
поделиться

Это известно как проблема алмаза , на странице есть запись на Python, но короче говоря, Python будет вызывать методы суперкласса слева направо.

51
ответ дан 22 November 2019 в 21:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: