2013-08-01 13 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): 
     ? 

Jak mogę uczynić konstruktorem AB wywołanie konstruktorów dla A i B z odpowiednimi argumentami?Wywołanie konstruktorów superklasy w python z różnymi argumentami

Próbowałem

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

ale to daje mi błąd.

+1

Dlaczego zamiast delegacji używasz dziedziczenia? Ponieważ przypadek wielokrotnego dziedziczenia powinien być obsługiwany za pomocą 'super', który nie będzie działał poprawnie z powodu różnych parametrów w' __init__'. – ovgolovin

+2

@ovgolovin Ponieważ jestem niedoświadczonym programistą. Nie wiem, co to jest delegacja. Spróbuję to przeanalizować. –

+0

@ovgolovin Dzięki. Okazało się, że rozwiązałem swój problem za pomocą opakowania. –

Odpowiedz

11

Nie przeszedłeś self.

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

Zauważ, że jeśli ta hierarchia dziedziczenia staje się bardziej skomplikowane, będziesz napotkasz problemy z konstruktorów nie wykonanie lub uzyskanie reexecuted. Zajrzyj do super (i problems z super) i nie zapomnij odziedziczyć po object, jeśli jesteś na 2.x i twoja klasa nie dziedziczy z niczego innego.

+0

Agh, taki głupi. Dziękuję Ci. –

10

Inne odpowiedzi sugerowały dodanie self do pierwszego parametru.

Ale zwykle wywołania __init__ w klasach nadrzędnych są wykonywane przez super.

Rozważmy następujący przykład:

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 klasa zawiera postanowienie, w którym konstruktorzy i initializators należy nazwie:

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

See, że pierwszy AB 's __init__ jest wywoływana, następnie B' s, następnie A, a następnie object. check

Miejmy:

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

Ale te rozmowy za pośrednictwem tej sieci są wykonane przez super. Kiedy wpisujemy super(AB, self), oznacza to: znajdź następną klasę po AB w __mro__ łańcuchu self.

Następnie powinniśmy powołać super w B, szukając następnej klasy w łańcuchu po B: super(B, self).

Ważne jest, aby używać super i nie nawiązywać ręcznie A.__init__(self,...) itd., Ponieważ może to później prowadzić do problemów. Read this for more info.

Tak więc, jeśli pozostaniesz z super, to jest problem. __init__ Metody w twoich klasach oczekują różnych parametrów. I nie wiesz na pewno, w jakiej kolejności super będzie wywoływał metody w tych klasach. Kolejność jest określana przez C3 algorithm w momencie tworzenia klasy. W podklasach inne klasy mogą łączyć się z łańcuchem wywołań. Więc nie można mieć różnych parametrów w __init__, ponieważ w tym przypadku zawsze będziesz musiał wziąć pod uwagę cały łańcuch dziedziczenia, aby zrozumieć, jak będą wywoływane metody.

Na przykład rozważ dodanie klas podrzędnych C(A) i D(B) oraz podklasy CD. Wtedy A nie będzie już wywoływany po B, ale po 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 

Więc myślę, że to dobry pomysł, aby myśleć o użyciu delegation zamiast dziedziczenia tutaj.

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

Więc, po prostu stworzyć a i b wystąpień A i B klas wewnątrz AB obiektu. A następnie mogą używać ich zgodnie z potrzebami, korzystając z metod, odnosząc się do self.a i self.b.

Aby skorzystać lub nie delegacja zależy od przypadku, który nie wynika z Twojego pytania. Ale może to być opcja do rozważenia.

Powiązane problemy