Подтвердить что ты не робот

Многоуровневое наследование Python, __init__

Что касается множественного родительского наследования, когда я вызываю 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
4b9b3361

Ответ 1

Если вы хотите использовать super в child для вызова parent.__init__ и parent2._init__, то оба родителя __init__ также должны вызвать 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)

Подробнее о последовательности вызовов __init__, вызванных использованием super, см. "Метод суперпотока Python и альтернативы вызова" .


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). Это вызывает a TypeError, поскольку object.__init__() не принимает параметров.

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

Ответ 3

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

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 class mro класс super ParentA равен ParentB, поэтому вам нужно вызвать super().__init__() в ParentA для init ParentB.

Если вы измените 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