2013-08-01 1 views
11
class A(): 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

class B(): 
    def __init__(self, z=0): 
     self.z = z 

class AB(A,B): 
    def __init__(self, x, y, z=0): 
     ? 

Wie kann ich den Konstruktor von AB veranlassen, die Konstruktoren für A und B mit den richtigen Argumenten aufzurufen?Aufruf von Superklassenkonstruktoren in Python mit verschiedenen Argumenten

Ich habe

versucht
class AB(A,B): 
    def __init__(self, x, y, z=0): 
     A.__init__(x,y) 
     B.__init__(z) 

aber das gibt mir einen Fehler.

+1

Warum verwenden Sie hier Vererbung anstelle von Delegation? Da der Fall der Mehrfachvererbung mit 'super' behandelt werden sollte, wird das wegen anderer Parameter in' ___init__' nicht gut funktionieren. – ovgolovin

+2

@ovgolovin Weil ich ein unerfahrener Programmierer bin. Ich weiß nicht, was Delegation ist. Ich werde versuchen, es zu untersuchen. –

+0

@ovgolovin Danke. Es stellte sich heraus, dass ich mein Problem mit einem Wrapper gelöst hatte. –

Antwort

11

Sie haben self nicht bestanden.

class AB(A, B): 
    def __init__(self, x, y, z=0): 
     A.__init__(self, x, y) 
     B.__init__(self, z) 

Beachten Sie, dass, wenn diese Vererbungshierarchie komplizierter wird, Sie Probleme werden mit Konstrukteuren nicht ausgeführt wird oder erneut ausgeführt zu werden. Schauen Sie in super (und die problems mit super), und vergessen Sie nicht, von object zu erben, wenn Sie auf 2.x sind und Ihre Klasse von nichts anderem erbt.

+0

Agh, so dumm. Danke. –

10

Andere Antworten vorgeschlagen, self zum ersten Parameter hinzuzufügen.

Aber normalerweise Aufrufe von __init__ in Elternklassen werden von super gemacht.

Betrachten Sie dieses Beispiel:

class A(object): 
    def __init__(self, x): 
     print('__init__ is called in A') 
     self.x = x 


class B(object): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in B') 
     super(B, self).__init__(*args, **kwargs) 


class AB(B, A): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in AB') 
     super(AB, self).__init__(*args, **kwargs) 

AB Klasse enthält eine Reihenfolge, in der Konstrukteurs und initializators sollte aufgerufen werden:

>>> AB.__mro__ 
(<class '__main__.AB'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>) 

See, dass erste AB 's __init__ aufgerufen wird, dann B' s, dann A 's, und dann object' s.

Lassen Sie uns:

>>> ab = AB(1) 
__init__ is called in AB 
__init__ is called in B 
__init__ is called in A 

Aber diese Anrufe durch diese Kette durch super gemacht. Wenn wir super(AB, self) eingeben, bedeutet das: Finde dann nächste Klasse nach AB in __mro__ Kette von self.

Dann sollten wir super in B, rufen Sie für die nächste Klasse in der Kette nach B suchen: super(B, self).

Es ist wichtig, super zu verwenden und nicht manuell A.__init__(self,...) usw. aufzurufen, da dies später zu Problemen führen kann. Read this for more info.

Also, wenn Sie mit super bleiben, dann gibt es ein Problem. __init__ Methoden in Ihren Klassen erwarten unterschiedliche Parameter. Und Sie können nicht sicher die Reihenfolge wissen, in der super Methoden in diesen Klassen aufrufen wird. Die Reihenfolge wird zum Zeitpunkt der Klassenerstellung durch C3 algorithm festgelegt. In Unterklassen können andere Klassen zwischen die Aufrufkette gelangen. Sie können also keine anderen Parameter in __init__ haben, da Sie in diesem Fall immer alle Vererbungsketten berücksichtigen müssen, um zu verstehen, wie __init__ Methoden aufgerufen werden.

Zum Beispiel in Betracht ziehen, C(A) und D(B) Klassen und CD Unterklasse von ihnen hinzuzufügen. Dann wird A nicht mehr nach B aufgerufen, sondern nach C.

class A(object): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in A') 
     super(A, self).__init__(*args, **kwargs) 


class B(object): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in B') 
     super(B, self).__init__(*args, **kwargs) 

class AB(B,A): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in AB') 
     super(AB, self).__init__(*args, **kwargs) 

class C(A): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in C') 
     super(C, self).__init__(*args, **kwargs) 

class D(B): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in D') 
     super(D, self).__init__(*args, **kwargs) 


class CD(D,C): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in CD') 
     super(CD, self).__init__(*args, **kwargs) 

class ABCD(CD,AB): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in ABCD') 
     super(ABCD, self).__init__(*args, **kwargs) 




>>> abcd = ABCD() 
__init__ is called in ABCD 
__init__ is called in CD 
__init__ is called in D 
__init__ is called in AB 
__init__ is called in B 
__init__ is called in C 
__init__ is called in A 

Also ich denke, es ist eine gute Idee, hier zu denken, über die Verwendung von delegation statt Vererbung.

class AB(object): 
    def __init__(self, x, y, z=0): 
     self.a = A(x,y) 
     self.b = B(z) 

So erstellen Sie nur a und b Instanzen von A und B Klassen innerhalb AB Objekt. Und dann können Sie sie verwenden, wie Sie durch Methoden unter Bezugnahme auf self.a und self.b benötigen.

Die Verwendung oder nicht Delegierung hängt von Ihrem Fall ab, der aus Ihrer Frage nicht klar ist. Aber es könnte eine Option sein, die es zu berücksichtigen gilt.