2013-08-13 10 views
43

ho scoperto di recente (via StackOverflow) che per chiamare un metodo in una classe di base che dovrei chiamare:Quando si chiama super() in una classe derivata, posso passare in self .__ class__?

super([[derived class]], self).[[base class method]]()

va bene, funziona. Tuttavia, mi trovo spesso a copiare e incollare tra le classi quando apporto una modifica e spesso dimentico di correggere l'argomento della classe derivata alla funzione super().

Vorrei evitare di dover ricordare di modificare l'argomento della classe derivata. Posso invece usare solo self.__class__ come primo argomento della funzione super()?

Sembra funzionare ma ci sono buoni motivi per cui non dovrei farlo?

risposta

71

No, non è possibile. La chiamata super() deve conoscere la classe di cui fa parte il metodo, per cercare le classi base per un metodo sottoposto a override.

Se si passa a self.__class__ (o meglio ancora, type(self)) poi super() è dato dalla parte del torto punto di partenzaper la ricerca di metodi, e finirà per chiamare di nuovoil proprio metodo.

Vedere come un puntatore nell'elenco di classi che formano la sequenza Ordine risoluzione metodo. Se si passa in type(self), il puntatore farà riferimento a qualsiasi sottoclasse anziché al punto di partenza originale.

Il seguente codice porta ad un errore ricorsione infinita:

class Base(object): 
    def method(self): 
     print 'original' 

class Derived(Base): 
    def method(self): 
     print 'derived' 
     super(type(self), self).method() 

class Subclass(Derived): 
    def method(self): 
     print 'subclass of derived' 
     super(Subclass, self).method() 

Demo:

>>> Subclass().method() 
subclass of derived 
derived 
derived 
derived 

<... *many* lines removed ...> 

    File "<stdin>", line 4, in method 
    File "<stdin>", line 4, in method 
    File "<stdin>", line 4, in method 
RuntimeError: maximum recursion depth exceeded while calling a Python object 

perché type(self) è Subclass, nonDerived, in Derived.method().

Nell'esempio, l'MRO per Subclass è [Subclass, Derived, Base] e super() deve sapere da dove iniziare la ricerca di metodi sovrascritti. Usando type(self), si dice di iniziare a Subclass, quindi troverà Derived.method() avanti, che è dove abbiamo iniziato.

+4

Eccellente, molto chiaro, spiegazione, grazie. –

9

self.__class__non essere una sottoclasse, ma piuttosto una classe nipote-o-giovane, che porta a un ciclo di rottura dello stack.

Problemi correlati