Множественное наследование: утечка требований к конструктору второго базового класса в конструктор первого базового класса - PullRequest
0 голосов
/ 10 октября 2018

Я пытаюсь наследовать от 2 базовых классов.

Конструктор первого базового класса (Base1) не принимает аргументов:

class Base1(object):
    def __init__(self):
        ...

Второй базовый класс (Base2) конструктор принимает один аргумент, id:

class Base2(object):
    def __init__(self, id):
        ...

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

class Deriv(Base1, Base2):
    def __init__(self):
        super(Base1, self).__init__()
        super(Base2, self).__init__("hello world")

Это происходит со следующей ошибкой:

    super(Base1, self).__init__()
TypeError: __init__() missing 1 required positional argument: 'id'

Как правильно вызвать каждый конструктор базового класса с правильным списком аргументов?

Вот пример приложения, которое воспроизводит ошибку, с которой я столкнулся:

#!/usr/bin/env python3

class Base1(object):
    def __init__(self):
        pass

class Base2(object):
    def __init__(self, id):
        self.id = id

class Deriv(Base1, Base2):
    def __init__(self):
        super(Base1, self).__init__()
        super(Base2, self).__init__("hello world")

def main():
    Deriv()

if __name__ == '__main__':
    main()

Вот трассировка:

Traceback (most recent call last):
  File "./test.py", line 20, in <module>
    main()
  File "./test.py", line 17, in main
    Deriv()
  File "./test.py", line 13, in __init__
    super(Base1, self).__init__()
TypeError: __init__() missing 1 required positional argument: 'id'

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Вы неправильно поняли, что делает super().super() принимает атрибут порядка разрешения методов __mro__ (последовательность) из типа self, затем находит позицию первого аргумента в этой последовательности, а затем начинает поиск после этой точки.

Для вашего случая Deriv.__mro__ это:

(<class '__main__.Deriv'>, <class '__main__.Base1'>, <class '__main__.Base2'>, <class 'object'>)

и super(Base1, self) начнет поиск метода __init__ для следующего объекта, здесь Base2, и super(Base2, self) найдетobject.Ошибка возникает потому, что Base2.__init__ должен принимать аргумент id, но super(Base1, self).__init__() не предоставляет этот аргумент.

Вместо этого вы хотите использовать кооперативное наследование и передавать аргументы цепочке вызовов:

class Base1(object):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

class Base2(object):
    def __init__(self, id, *args, **kwargs):
        self.id = id
        super().__init__(*args, **kwargs)

class Deriv(Base1, Base2):
    def __init__(self):
        super().__init__("hello world")

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

class Base1(object):
    def __init__(self):
        pass

class Base2(object):
    def __init__(self, id):
        self.id = id

class Deriv(Base1, Base2):
    def __init__(self):
        Base1.__init__(self)
        Base2.__init__(self, "hello world")
0 голосов
/ 10 октября 2018

Вы используете неправильные первые аргументы для super:

def __init__(self):
    super(Deriv, self).__init__()
    super(Base1, self).__init__("Hello world")

Обратите внимание, однако, что это работает только потому, что Base1.__init__ само по себе не использует super, потому что если это так, то онобудет пытаться вызвать Base2.__init__, так как это следующий метод в MRO исходного объекта.

Первый аргумент super сообщает вам после , какой класс в MROначните искать нужный атрибут.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...