2013-08-13 11 views
43

I niedawno odkryte (przez StackOverflow), że do wywołania metody w klasie bazowej powinienem zadzwonić:Podczas wywoływania super() w klasie pochodnej, czy mogę przekazać self .__ class__?

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

To dobrze, to działa. Jednak często znajduję się kopiowanie i wklejanie między klasami, gdy dokonuję zmiany i często zapominam naprawić argument klasy pochodnej do funkcji super().

Chciałbym uniknąć konieczności pamiętania, aby zmienić argument klasy pochodnej. Czy zamiast tego mogę po prostu użyć self.__class__ jako pierwszego argumentu funkcji super()?

Wydaje się działać, ale czy istnieją uzasadnione powody, dla których nie powinienem tego robić?

Odpowiedz

71

Nie, nie możesz. Wywołanie super() musi wiedzieć, do której klasy należy ta metoda, aby przeszukać klasy bazowe dla nadpisanej metody.

Jeśli przechodzą w self.__class__ (albo jeszcze lepiej, type(self)) następnie super() otrzymuje niewłaściwy punkt początkową by szukać sposobów, a zakończy się ponownie nazywając własną metodę.

Zobacz go jako wskaźnik na liście klas, które tworzą kolejność kolejności rozstrzygania metod. Jeśli przejdziesz w type(self), wskaźnik będzie odwoływał się do wszystkich podklas zamiast oryginalnego punktu początkowego.

Poniższy kod prowadzi do błędu nieskończonej rekurencji:

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 

ponieważ type(self) jest Subclass, nieDerived w Derived.method().

W tym przykładzie numer MRO dla Subclass to [Subclass, Derived, Base], a super() musi wiedzieć, od czego zacząć wyszukiwanie jakichkolwiek nadpisanych metod. Korzystając z type(self), mówisz, że zaczynasz od Subclass, więc następnym razem znajdzie się Derived.method(), od której zaczęliśmy.

+4

Doskonałe, bardzo jasne, wyjaśnienie, dzięki. –

9

self.__class__ może nie być podklasą, ale raczej klasą wnukową lub młodszą, prowadzącą do pętli przełamującej stos.

Powiązane problemy