web-dev-qa-db-ja.com

Python multi-inheritance、__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
27
Renl

superchildを使用して_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)
_

superを使用したことによる___init___の呼び出しシーケンスの詳細については、 "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)を呼び出します。 object.__init__()はパラメーターを取らないため、これによりTypeErrorが発生します。

この問題を回避するには、___init___への引数を受け入れるが_object.__init___に渡さないクラスBaseを作成します。 parentと_parent2_をBaseから継承すると、TypeErrorを回避できます。

26
unutbu

parentメソッド解決順序(MRO) の次であり、super()を使用してparent2を呼び出すことはないためです。

この例を見てください:

_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では、superParentAクラスはParentBなので、次の呼び出しが必要ですParentAsuper().__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 [〜#〜] の詳細

5
Steely Wing