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

Come posso far sì che il costruttore di AB chiami i costruttori per A e B con gli argomenti appropriati?Chiamare i costruttori di superclasse in python con diversi argomenti

Ho provato

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

ma questo mi dà un errore.

+1

Perché usi qui l'ereditarietà anziché la delega? Perché il caso dell'ereditarietà multipla dovrebbe essere gestito usando 'super', che non funzionerà bene a causa dei diversi parametri in' __init__'. – ovgolovin

+2

@ovgolovin Perché sono un programmatore inesperto. Non so cosa sia la delega. Proverò a esaminarlo. –

+0

@ovgolovin Grazie. Si è scoperto che ho risolto il mio problema con un wrapper. –

risposta

11

Non hai superato self.

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

Nota che se questa gerarchia di ereditarietà diventa più complicato, si incorrerà in problemi con i costruttori non esecuzione o di ottenere eseguito nuovamente. Esaminare super (e lo problems con super) e non dimenticare di ereditare da object se si è su 2.x e la classe non eredita da altro.

+0

Agh, così stupido. grazie. –

10

Altre risposte suggerite aggiungendo self al primo parametro.

Ma solitamente le chiamate di __init__ nelle classi parent sono fatte da super.

Considerate questo esempio:

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 classe contiene un ordine in cui i costruttori e initializators dovrebbero essere chiamati:

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

Sede, che prima AB 's __init__ viene invocato, poi B' s, quindi A e quindi object. controllo

Let:

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

Ma queste chiamate attraverso questa catena sono fatte da super. Quando digitiamo super(AB, self), significa: trova la classe successiva dopo AB nella catena __mro__ di self.

Allora dovremmo invocare super in B, cercando la classe successiva nella catena dopo B: super(B, self).

È importante utilizzare super e non chiamare manualmente A.__init__(self,...), ecc., Poiché potrebbe causare problemi in seguito. Read this for more info.

Quindi, se si rimane con super, c'è un problema. I metodi __init__ nelle tue classi prevedono parametri diversi. E non puoi sapere con certezza l'ordine in cui super invocherà metodi in queste classi. L'ordine è determinato da C3 algorithm al momento della creazione della classe. Nelle sottoclassi, altre classi possono ottenere tra la catena di chiamate. Pertanto non è possibile avere parametri diversi in __init__, poiché in questo caso si dovrà sempre considerare tutta la catena di ereditarietà per capire come verranno chiamati i metodi __init__.

Ad esempio, considerare l'aggiunta di classi C(A) e D(B) e di sottoclasse CD. Quindi A non verrà più richiamato dopo B, ma dopo 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 

Quindi penso che sia una buona idea pensare di utilizzare delegation invece di eredità qui.

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

Quindi, basta creare a e b istanze di A e B classi all'interno AB oggetto. E quindi possono usarli come necessario attraverso i metodi facendo riferimento a self.a e self.b.

Per utilizzare o meno la delega dipende dal vostro caso che non è chiaro dalla vostra domanda. Ma potrebbe essere un'opzione da considerare.

Problemi correlati