2009-09-06 12 views
96

Sono abituato che in Objective-C Ho questo costrutto:Dovrebbe __init __() chiamare __init __() della classe genitore?

- (void)init { 
    if (self = [super init]) { 
     // init class 
    } 
    return self; 
} 

Qualora Python anche chiamare l'implementazione madre di classe per __init__?

class NewClass(SomeOtherClass): 
    def __init__(self): 
     SomeOtherClass.__init__(self) 
     # init class 

È questo anche vero/falso per __new__() e __del__()?

Edit: C'è una domanda molto simile: Inheritance and Overriding __init__ in Python

+0

hai cambiato il codice in modo significativo. Posso capire che l'originale 'oggetto' era un refuso. Ma ora non hai nemmeno il titolo "super" della tua domanda. – SilentGhost

+0

Ho appena pensato che super sia usato come nome per la classe genitore. Non pensavo che qualcuno avrebbe pensato alla funzione. Mi dispiace per eventuali equivoci. –

+0

Una domanda di super chiamata automatica: http://stackoverflow.com/questions/3782827/why-arent-pythons-superclass-init-methods-automatically-invoked –

risposta

48

In Python, chiamare la classe super '__init__ è facoltativo. Se tu lo chiami, è poi anche facoltativa se utilizzare l'identificatore super, o se per citarne esplicitamente la classe super:

object.__init__(self) 

In caso di oggetti, chiamando il metodo eccellente non è strettamente necessaria, dal momento che il super il metodo è vuoto Lo stesso per __del__.

OTOH, per __new__, dovresti chiamare il metodo super e usare il suo ritorno come oggetto appena creato - a meno che tu non voglia esplicitamente restituire qualcosa di diverso.

+0

Quindi non c'è convenzione per chiamare l'implementazione di super? –

+4

Nelle classi vecchio stile, è possibile chiamare solo il super __init__ se la super classe ha effettivamente definito __init__ (che spesso non lo è). Pertanto, le persone in genere pensano di chiamare il metodo super, piuttosto che farlo per principio. –

+1

Se la sintassi in python fosse semplice come '[super init]', sarebbe più comune. Solo un pensiero speculativo; il super costrutto in Python 2.x è un po 'imbarazzante per me. – u0b34a0f6ae

17

Edit: (dopo la modifica del codice)
Non c'è modo per noi dire se è necessario o meno di chiamare il genitore di __init__ (o qualsiasi altra funzione). L'ereditarietà ovviamente funzionerebbe senza tale chiamata. Tutto dipende dalla logica del tuo codice: ad esempio, se tutto il tuo __init__ viene eseguito nella classe genitore, puoi semplicemente saltare a livello di figlio __init__ del tutto.

consideri il seguente esempio:

>>> class A: 
    def __init__(self, val): 
     self.a = val 


>>> class B(A): 
    pass 

>>> class C(A): 
    def __init__(self, val): 
     A.__init__(self, val) 
     self.a += val 


>>> A(4).a 
4 
>>> B(5).a 
5 
>>> C(6).a 
12 
+0

Ho rimosso la super chiamata dal mio esempio, volevo sapere se si dovrebbe chiamare l'implementazione della classe genitore di __init__ oppure no. –

+0

quindi potresti voler modificare il titolo. ma la mia risposta è ancora valida. – SilentGhost

4

Non esiste una regola dura e veloce. La documentazione per una classe dovrebbe indicare se le sottoclassi dovrebbero chiamare il metodo della superclasse. A volte si desidera sostituire completamente il comportamento della superclasse e altre volte aumentarlo, ovvero chiamare il proprio codice prima e/o dopo una chiamata della superclasse.

Aggiornamento: La stessa logica di base si applica a qualsiasi chiamata di metodo. I costruttori a volte hanno bisogno di considerazioni speciali (come spesso impostano lo stato che determina il comportamento) e distruttori perché sono costruttori paralleli (ad esempio nell'assegnazione delle risorse, ad esempio le connessioni al database). Ma lo stesso potrebbe applicarsi, per esempio, al metodo render() di un widget.

Ulteriore aggiornamento: Che cos'è l'OPP? Intendi OOP? No - una sottoclasse spesso ha bisogno di sapere qualcosa sul sul design della superclasse. Non i dettagli di implementazione interna, ma il contratto base che la superclasse ha con i suoi clienti (usando le classi). Ciò non viola in alcun modo i principi OOP. Ecco perché protected è un concetto valido in OOP in generale (sebbene non, ovviamente, in Python).

+0

Che ne dici di nuovo e del? –

+0

Hai detto che a volte uno vorrebbe chiamare il proprio codice prima della chiamata della superclasse. Per fare ciò, è necessario conoscere l'implementazione della classe genitore, che violerebbe l'OPP. –

3

IMO, dovresti chiamarlo. Se la tua superclasse è object, non dovresti, ma in altri casi penso che sia eccezionale non chiamarla.Come già risposto da altri, è molto conveniente se la classe non ha nemmeno la precedenza su __init__, ad esempio quando non ha uno stato interno (aggiuntivo) da inizializzare.

107

Se è necessario eseguire qualcosa da __init__ di super in aggiunta a ciò che viene eseguito nella classe corrente __init__,, è necessario chiamare da sé, poiché ciò non avverrà automaticamente. Ma se non hai bisogno di nulla da Super's __init__, non c'è bisogno di chiamarlo. Esempio:

>>> class C(object): 
    def __init__(self): 
     self.b = 1 


>>> class D(C): 
    def __init__(self): 
     super().__init__() # in Python 2 use super(D, self).__init__() 
     self.a = 1 


>>> class E(C): 
    def __init__(self): 
     self.a = 1 


>>> d = D() 
>>> d.a 
1 
>>> d.b # This works because of the call to super's init 
1 
>>> e = E() 
>>> e.a 
1 
>>> e.b # This is going to fail since nothing in E initializes b... 
Traceback (most recent call last): 
    File "<pyshell#70>", line 1, in <module> 
    e.b # This is going to fail since nothing in E initializes b... 
AttributeError: 'E' object has no attribute 'b' 

__del__ è allo stesso modo, (ma diffidare di fare affidamento su __del__ per la finalizzazione - in considerazione di farlo tramite l'istruzione with invece).

Io uso raramente __new__. faccio tutto l'inizializzazione in __init__.

+2

La definizione di classe D (C) deve essere corretta in questo modo '' super (D, self) .__ init __() '' – eyquem

+9

super() .__ init __() funziona solo in Python 3. In Python 2 è necessario super (D , self) .__ init __() – Jacinda

62

In risposta di Anon:
"Se avete bisogno di qualcosa da super di __init__ essere fatto in aggiunta a ciò che viene fatto nel corso di classe del __init__, lo devi chiamare tu stesso, dal momento che ciò non avverrà automaticamente "

È incredibile: sta formulando esattamente il contrario del principio di ereditarietà.


Non è che "qualcosa da super __init__ (...) non accadrà automaticamente", è che sarebbe accaduto automaticamente, ma non accade perché la classe base '__init__ viene sovrascritto dalla definizione delle Classe di selezione derivati ​​__init__

Così allora, perchè la definizione di un Derived_Class' __init__, dal momento che ignora ciò che è finalizzato a quando qualcuno ricorre alla successione ??

È perché è necessario definire qualcosa che NON viene eseguito nella classe base '__init__ e l'unica possibilità di ottenerlo è di mettere la sua esecuzione in una funzione di classe derivata' __init__.
In altre parole, uno ha bisogno di qualcosa in classe base '__init__ in aggiunta a in quello che verrebbe eseguito automaticamente nella classe base' __init__ se quest'ultimo non è stato sostituito.
NON è il contrario.


Quindi, il problema è che le istruzioni desiderati presenti nella classe base __init__ non sono più attivati ​​al momento di istanziazione. Per compensare questa inattivazione, è necessario qualcosa di speciale: chiamare esplicitamente la classe base '__init__, al fine di KEEP, NON AGGIUNGERE, l'inizializzazione eseguita dalla classe base' __init__. Questo è esattamente ciò che viene detto nel documento ufficiale:

Un metodo imperativo di una classe derivata può in effetti voler estendere la piuttosto che semplicemente sostituire il metodo della classe base con lo stesso nome. C'è un modo semplice per chiamare direttamente il metodo della classe base: solo chiama BaseClassName.methodname (self, argomenti).
http://docs.python.org/tutorial/classes.html#inheritance

Questo è tutto la storia:

  • quando l'obiettivo è quello di mantenere l'inizializzazione eseguita dal classe base, vale a dire l'ereditarietà pura, niente di speciale è necessaria, si deve solo evitare per definire una funzione __init__ nella classe derivata

  • quando lo scopo è di SOSTITUIRE l'inizializzazione eseguita dalla classe base, __init__ deve essere definito in e classe derivata

  • quando l'obiettivo è quello di aggiungere i processi per l'inizializzazione eseguita da classe base, una classe derivata __init__ deve essere definita, comprendente una chiamata esplicita alla classe base __init__


quello che sento sorprendente nel post di Anon è non solo che egli esprime al contrario della teoria eredità, ma che ci sono stati 5 ragazzi di passaggio che upvoted senza girare un capello, e inoltre ci sono stato nessuno a reagire in 2 anni in un thread il cui argomento interessante deve essere letto relativamente spesso.

+1

Ero sicuro che questo post sarebbe stato upvoted. Ho paura che non avrò molte spiegazioni sui motivi per cui. È più semplice effettuare lo downvoting piuttosto che analizzare un testo che sembra incomprensibile. Ho avuto molto tempo a cercare di capire il post di Anon prima di rendermi finalmente conto che era scritto in modo specioso e non molto autorevole.Forse può essere interpretato come approssimativamente giusto per qualcuno che sa dell'eredità; ma trovo confusionario quando viene letto da qualcuno che ha nozioni incerte sull'ereditarietà, un argomento non chiaro come l'acqua di roccia in generale – eyquem

+1

"Ero sicuro che questo post avrebbe dovuto essere svalutato ..." Il problema principale è che tu sei un Poco in ritardo alla festa, e molte persone potrebbero non leggere oltre le prime poche risposte. Ottima spiegazione tra l'altro +1 – Gerrat

+0

Ottima risposta. – Trilarion

Problemi correlati