2009-05-24 13 views
242

Considera questo: una classe base A, una classe B che eredita da A, una classe C che eredita da B. Qual è un modo generico per chiamare un costruttore della classe genitore in un costruttore? Se questo sembra ancora troppo vago, ecco un codice.Costruttori genitore di chiamate in catena in python

class A(object): 
    def __init__(self): 
     print "Constructor A was called" 

class B(A): 
    def __init__(self): 
     super(B,self).__init__() 
     print "Constructor B was called" 

class C(B): 
    def __init__(self): 
     super(C,self).__init__() 
     print "Constructor C was called" 

c = C() 

Ecco come lo faccio ora. Ma sembra ancora un po 'troppo generico - devi ancora passare un tipo corretto a mano.

Ora, ho provato a usare self.__class__ come un primo argomento a super(), ma, ovviamente, non funziona - se lo si inserisce nel costruttore per C - abbastanza corretto, viene chiamato il costruttore di B. Se fai lo stesso in B, "self" punta ancora a un'istanza di C così finisci per chiamare di nuovo il costruttore di B (questo termina con una ricorsione infinita).

Non c'è bisogno di pensare all'ereditarietà del diamante per ora, sono solo interessato a risolvere questo problema specifico.

+0

"Ma sembra ancora un po 'troppo non generico - si ancora deve passare un tipo corretto a mano. "?? Stai passando il nome della classe a super(). Non hai mai bisogno di conoscere la superclasse o qualsiasi altra cosa. Come è questo non generico? Che problema crea? Puoi dare un esempio dove questo si rompe? –

+3

Non sono pronto a rispondere a questa domanda se è completo. Ma comunque, cosa succede se la classe viene ribattezzata? Cosa succede se voglio scrivere una funzione di decoratore per automatizzare questo tipo di concatenamento? Ora vedo che non è possibile, ma al momento di fare la domanda non lo sapevo. – shylent

risposta

151

Il modo in cui lo si sta facendo è davvero consigliato (per Python 2.x).

Il problema se la classe è passata esplicitamente a super è una questione di stile piuttosto che di funzionalità. Passare la classe a super si adatta alla filosofia di Python di "esplicitare è meglio di implicito".

+3

Ho avuto davvero molto tempo per decidere quale risposta accettare, ma accetterò questa, semplicemente perché è rilevante per la versione di Python che sto usando. – shylent

+9

In Python 2.6 ottengo 'TypeError: super() l'argomento 1 deve essere type, not classobj' che usa questo metodo. Mi sto perdendo qualcosa? – Leopd

+12

@Leopd: 'super()' funziona solo con classi di nuovo stile, vale a dire che devi ereditare da 'object'. –

159

Python 3 include un migliorato super(), che permette l'uso in questo modo:

super().__init__(args) 
+0

se ho più di una classe genitore come sarà Super identificare quale classe genitore invocare? – Kracekumar

+2

@kracekumar Sarà determinato dalla classe 'Metodo Risoluzione ordine (MRO), che è possibile scoprire chiamando 'MyClassName.mro()'. Potrei non essere corretto, ma credo che il primo genitore specificato sia quello il cui '__init__' sarà chiamato. –

+0

@ironfroggy, ti dispiacerebbe elaborare in che modo questo aiuto è migliorato con la domanda? Ho appena trovato questo thread vecchio e sto facendo le stesse domande esatte. Anche le cose sono migliorate per Python 2.x dal momento che questa domanda è stata posta per la prima volta? –

22

si può semplicemente scrivere:

class A(object): 

    def __init__(self): 
     print "Constructor A was called" 

class B(A): 

    def __init__(self): 
     A.__init__(self) 
     # A.__init__(self,<parameters>) if you want to call with parameters 
     print "Constructor B was called" 

class C(B): 

    def __init__(self): 
     # A.__init__(self) # if you want to call most super class... 
     B.__init__(self) 
     print "Constructor C was called" 
Problemi correlati