Мульти-наследование Python, __init__ - PullRequest
27 голосов
/ 31 декабря 2011

Что касается множественного родительского наследования, когда я вызываю super. __init__, почему функция parent2 __init__ не вызывается?Спасибо.

class parent(object):
    var1=1
    var2=2
    def __init__(self,x=1,y=2):
        self.var1=x
        self.var2=y

class parent2(object):
    var4=11
    var5=12
    def __init__(self,x=3,y=4):
        self.var4=x
        self.var5=y

    def parprint(self):
        print self.var4
        print self.var5

class child(parent, parent2):
    var3=5
    def __init__(self,x,y):
        super(child, self).__init__(x,y)

childobject = child(9,10)
print childobject.var1
print childobject.var2
print childobject.var3
childobject.parprint()

Вывод

9
10
5
11
12

Ответы [ 3 ]

26 голосов
/ 31 декабря 2011

Если вы хотите использовать super в child для вызова parent.__init__ и parent2._init__, то оба родителя __init__ s должны также вызвать super:

class parent(Base):
    def __init__(self,x=1,y=2):
        super(parent,self).__init__(x,y)   

class parent2(Base):
    def __init__(self,x=3,y=4):
        super(parent2,self).__init__(x,y)

См. "Супер-метод Python и альтернативные вызовы" для более подробной информации о последовательности вызовов __init__, вызванных использованием super.


class Base(object): 
    def __init__(self,*args):
        pass

class parent(Base):
    var1=1
    var2=2
    def __init__(self,x=1,y=2):
        super(parent,self).__init__(x,y)        
        self.var1=x
        self.var2=y

class parent2(Base):
    var4=11
    var5=12
    def __init__(self,x=3,y=4):
        super(parent2,self).__init__(x,y)
        self.var4=x
        self.var5=y

    def parprint(self):
        print self.var4
        print self.var5

class child(parent, parent2):
    var3=5
    def __init__(self,x,y):
        super(child, self).__init__(x,y)


childobject = child(9,10)
print childobject.var1
print childobject.var2
print childobject.var3
childobject.parprint()

Вы можете спросить: «Зачем использовать Base?». Если parent и parent2 унаследованы непосредственно от object, то super(parent2,self).__init__(x,y) будет звонить object.__init__(x,y). Это поднимает TypeError, поскольку object.__init__() не принимает параметров.

Чтобы обойти эту проблему, вы можете создать класс Base, который принимает аргументы для __init__, но не передает их object.__init__. С parent и parent2, наследуемыми от Base, вы избегаете TypeError.

9 голосов
/ 31 декабря 2011

Поскольку parent следующий в порядке разрешения методов (MRO) , и он никогда не использует super() для вызова parent2.

5 голосов
/ 19 марта 2014

См. Этот пример:

class Base(object): 
    def __init__(self, c):
        print('Base called by {0}'.format(c))
        super().__init__()

class ParentA(Base):
    def __init__(self, c):
        print('ParentA called by {0}'.format(c))
        super().__init__('ParentA')

class ParentB(Base):
    def __init__(self, c):
        print('ParentB called by {0}'.format(c))
        super().__init__('ParentB')

class Child(ParentA, ParentB):
    def __init__(self, c):
        print('Child called by {0}'.format(c))
        super().__init__('Child')

Child('Construct')
print(Child.mro())

Будет выведено:

Child called by Construct
ParentA called by Child
ParentB called by ParentA
Base called by ParentB
[<class '__main__.Child'>, <class '__main__.ParentA'>, <class '__main__.ParentB'>, <class '__main__.Base'>, <class 'object'>]

Множественное наследование Python похоже на цепочку, в Child классе mro класс super для ParentA равен ParentB, поэтому для инициализации ParentB необходимо вызвать super().__init__() в ParentA .

Если вы измените super().__init__('ParentA') на Base.__init__(self, 'ParentA'), это приведет к разрыву цепочки наследования, вывод:

Child called by Construct
ParentA called by Child
Base called by ParentA
[<class '__main__.Child'>, <class '__main__.ParentA'>, <class '__main__.ParentB'>, <class '__main__.Base'>, <class 'object'>]

Подробнее о MRO

...