2013-07-07 31 views
21

Sto cercando di capire quando e come utilizzare super() in Python correttamente (o 2.7.x o 3.x)Argomenti Python super(): perché non super (obj)?

sul >>> help(super) l'interprete mi dice come chiamare è:

class super(object) 
| super(type) -> unbound super object 
| super(type, obj) -> bound super object; requires isinstance(obj, type) 
| super(type, type2) -> bound super object; requires issubclass(type2, type) 

Capisco che in Python3.x sia ora possibile utilizzare jusute super() all'interno di una definizione di classe, ma non capisco perché super(obj) non sia possibile. Oppure super(self) all'interno di una definizione di classe.

So che ci deve essere una ragione per questo, ma non riesco a trovarlo. Per me quelle righe equivalgono a super(obj.__class__, obj) o super(self.__class__, self) e quelle funzionerebbero correttamente?

Penso che scrivere semplicemente super(obj) sia una bella scorciatoia anche in Python 3.x.

+0

Stavo per dire che causerebbe ambiguità quando chiami 'super' su un metaclasse, ma poi mi sono reso conto che quell'ambiguità esiste anche con il modulo a 2 argomenti. Ora non sono sicuro. – user2357112

risposta

31

Il modulo a due argomenti è necessario solo in Python 2. Il motivo è che self.__class__ fa sempre riferimento alla classe "leaf" nell'albero di ereditarietà, ovvero la classe più specifica dell'oggetto, ma quando si chiama il numero super per indicare quale implementazione è attualmente invocata, in modo che possa invocare la successiva nell'albero di ereditarietà.

Supponiamo di avere:

class A(object): 
    def foo(self): 
     pass 

class B(A): 
    def foo(self): 
     super(self.__class__, self).foo() 

class C(B): 
    def foo(self): 
     super(self.__class__, self).foo() 

c = C() 

noti che c.__class__ è C, sempre. Ora pensa a cosa succede se chiami c.foo().

Quando si chiama super(self.__class__, self) in un metodo di C, sarà come chiamare super(C, self), che significa "chiamare la versione di questo metodo ereditato da C". Questo chiamerà B.foo, che va bene. Ma quando chiami super(self.__class__, self) da B, è ancora come chiamare super(C, self), perché è lo stesso self, quindi self.__class__ è ancora C. Il risultato è che la chiamata in B chiamerà nuovamente B.foo e si verificherà una ricorsione infinita.

Ovviamente, ciò che si vuole veramente è poter chiamare super(classThatDefinedTheImplementationThatIsCurrentlyExecuting, self), ed è proprio ciò che fa Python 3 super().

In Python 3, puoi semplicemente fare super().foo() e fa la cosa giusta. Non mi è chiaro cosa intendi per super(self) come scorciatoia. In Python 2, non funziona per la ragione che ho descritto sopra. In Python 3, sarebbe un "longcut" perché puoi semplicemente usare il semplice super().

Gli usi super(type) e super(type1, type2) potrebbero essere ancora necessari occasionalmente in Python 3, ma quelli erano sempre usi più esoterici per situazioni insolite.

+0

Un collaboratore ha refactored un pezzo di un metodo che ha chiamato 'super' in un metodo separato in un'altra classe, quindi il codice ha finito per dire' super (SomeOtherClass, some_obj) .method (...) 'Questo ha funzionato perfettamente, ma sembrava proprio un bug per chiunque leggesse il codice. Sebbene questo potesse essere (e finì per essere) espresso meglio, la forma a due argomenti di 'super' può ancora essere utile in alcuni casi limite. – user4815162342

+0

Le prime 4 righe della tua spiegazione mi hanno fatto capire tutto. Grazie per l'esempio. Quello era il pezzo mancante che stavo cercando di capire. – Gabriel

+0

Continuiamo a fare riferimento a un caso "esoterico" o "limite". Questo è semplicemente quando la doppia ereditarietà richiede di chiamare due separate funzioni '__init __()' quando si esegue l'override di '__init __()' nella classe foglia? –

0

Cercando una risposta breve:

self.__class__ è sempre il vero e proprio ("sub-più") di classe dell'istanza oggetto - non necessariamente la classe ricercato, che implementa la funzione!

Sostituisci super(self.__class__, self) con super(__class__, self) e hai ragione in una definizione di metodo in Python 3, perché Python 3 fornisce la variabile di cella magica __class__ per la classe di implementazione.

E semplicemente super() con argomenti zero è già la scorciatoia per super(__class__, self) in Python 3. Vedere PEP3135.

Python 2 non conosce __class__ né il collegamento di argomento zero super().

Problemi correlati