Python super () solleva TypeError


109

In Python 2.5, il codice seguente genera un TypeError:

>>> class X:
      def a(self):
        print "a"

>>> class Y(X):
      def a(self):
        super(Y,self).a()
        print "b"

>>> c = Y()
>>> c.a()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in a
TypeError: super() argument 1 must be type, not classobj

Se sostituisco il class Xcon class X(object), funzionerà. Qual è la spiegazione per questo?


3
il tuo "comunque sostituisco la classe X con la classe X (oggetto)" ha risolto il mio problema! grazie
AliBZ

Risposte:


132

Il motivo è che super()opera solo su classi di nuovo stile , che nella serie 2.x significa estendersi da object:

>>> class X(object):
        def a(self):
            print 'a'

>>> class Y(X):
        def a(self):
            super(Y, self).a()
            print 'b'

>>> c = Y()
>>> c.a()
a
b

4
Da quale versione di Python questo è diventato un comportamento predefinito?
Geo

6
2.2 è stato quando sono state introdotte le classi di nuovo stile, 3.0 è dove sono diventate quelle predefinite.
Cody Brocious,

7
@tsunami se vuoi partecipare alla superclasse, fai "Xa (self)"
James Brady

Penso che tu mi abbia frainteso . Trittico. Ricordo che stavo usando una versione di python inferiore alla 3.0 e non ho detto specificamente che la mia classe eredita da Object e la chiamata a super ha funzionato. Forse è il comportamento predefinito da 2.6? Sto solo dicendo :)
Geo

Alabastro, non ce n'è davvero bisogno. Le classi di nuovo stile hanno un numero enorme di vantaggi, non solo super. I metodi vecchio stile non dovrebbero essere promossi.
Cody Brocious,

14

Inoltre, non usare super () a meno che non sia necessario. Non è la "cosa giusta" generica da fare con le classi di nuovo stile che potresti sospettare.

Ci sono momenti in cui ti aspetti un'eredità multipla e potresti desiderarla, ma finché non conosci i dettagli pelosi dell'MRO, è meglio lasciarlo stare e attenersi a:

 X.a(self)

2
è corretto perché nei miei 6 mesi di Python / Django ho usato super come "la cosa giusta da fare in generale"?
philgo20

1
Beh, non ti fa male per l'eredità singola in sé (tranne per il fatto che è un po 'più lento), ma non ti dà nulla da solo. Devi progettare tutti i metodi che necessitano di ereditarietà multipla (in particolare __init__) per passare attraverso gli argomenti in modo pulito e ragionevole, altrimenti otterrai TypeErrors o problemi di debug peggiori quando qualcuno prova a moltiplicare-ereditare usando la tua classe. A meno che tu non abbia davvero progettato per supportare MI in questo modo (che è abbastanza complicato), è probabilmente meglio evitare l'implicazione superche il metodo sia sicuro per MI.
bobince

3

Nel caso in cui nessuna delle risposte precedenti lo menzionasse chiaramente. La tua classe genitore deve ereditare da "object", che essenzialmente la trasformerebbe in una nuova classe di stile.

# python 3.x:
class ClassName(object): # This is a new style class
    pass

class ClassName: # This is also a new style class ( implicit inheritance from object )
    pass

# Python 2.x:
class ClassName(object): # This is a new style class
    pass

class ClassName:         # This is a old style class
    pass

Spiacenti, ma in Python 3.x il tuo secondo esempio (ereditarietà implicita) non funziona davvero nel contesto del problema menzionato.
sophros il

1

Ho provato i vari metodi Xa (); tuttavia, sembrano richiedere un'istanza di X per eseguire a (), quindi ho fatto X (). a (self), che sembra più completo delle risposte precedenti, almeno per le applicazioni che ho incontrato. Non sembra essere un buon modo per gestire il problema poiché ci sono costruzioni e distruzioni non necessarie, ma funziona bene.

La mia applicazione specifica era il modulo cmd.Cmd di Python, che evidentemente non è un oggetto NewStyle per qualche motivo.

Risultato finale:

X().a(self)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.