super () non riesce con errore: TypeError "l'argomento 1 deve essere type, non classobj" quando parent non eredita dall'oggetto


196

Ottengo un errore che non riesco a capire. Qualche idea di cosa non vada nel mio codice di esempio?

class B:
    def meth(self, arg):
        print arg

class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)

print C().meth(1)

Ho ottenuto il codice di prova di esempio dall'aiuto del metodo incorporato "super".

Ecco l'errore:

Traceback (most recent call last):
  File "./test.py", line 10, in ?
    print C().meth(1)
  File "./test.py", line 8, in meth
    super(C, self).meth(arg)
TypeError: super() argument 1 must be type, not classobj

Cordiali saluti, ecco l'aiuto (super) di Python stesso:

Help on class super in module __builtin__:

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)
 |  Typical use to call a cooperative superclass method:
 |  class C(B):
 |      def meth(self, arg):
 |          super(C, self).meth(arg)
 |


3
Meth ?? È un termine di programmazione o ... sai? Si prega di precisare.
Cplusplusplus,

3
@Cplusplusplus: probabilmente sta per Method ;-)
ShadowFlame,

Risposte:


333

Il tuo problema è che la classe B non è dichiarata come una classe di "nuovo stile". Modificalo in questo modo:

class B(object):

e funzionerà.

super()e tutte le cose di sottoclasse / superclasse funzionano solo con classi di nuovo stile. Ti consiglio di prendere l'abitudine di scriverlo sempre (object)su qualsiasi definizione di classe per assicurarti che sia una classe di nuovo stile.

Le classi vecchio stile (note anche come classi "classiche") sono sempre di tipo classobj; le classi di nuovo stile sono di tipo type. Ecco perché hai ricevuto il messaggio di errore che hai visualizzato:

TypeError: super() argument 1 must be type, not classobj

Prova questo per vedere di persona:

class OldStyle:
    pass

class NewStyle(object):
    pass

print type(OldStyle)  # prints: <type 'classobj'>

print type(NewStyle) # prints <type 'type'>

Nota che in Python 3.x, tutte le classi sono di nuovo stile. Puoi ancora usare la sintassi delle classi di vecchio stile ma ottieni una nuova classe di stile. Quindi, in Python 3.x non avrai questo problema.


interessante, ho trovato questo esatto problema eseguendo bottle.py ( bottlepy.org ) che genera un errore simile (TypeError: deve essere di tipo, non classobj) in esecuzione su Py27 ma non su Py33.
Bootload

In Python 3.x non ci sono più classi "vecchio stile". Il codice che utilizza la dichiarazione "vecchio stile" dichiara ancora una classe "nuovo stile", quindi questo errore non può verificarsi in Python 3.x.
Steveha,

1
Se la classe B non è disponibile per la modifica, è necessario modificare la classe A per non provare a utilizzare super(); la classe A deve essere fatta funzionare con una classe "vecchio stile", e forse il modo migliore per farlo sarebbe quello di rendere la classe A stessa una classe "vecchio stile". Ovviamente consiglio di aggiornare l'intero programma per l'esecuzione in Python 3.x, in modo che tutte le classi siano di nuovo stile, indipendentemente da ciò che fai; se tale opzione è disponibile è l'opzione migliore.
Steveha,

Ho lo stesso problema, ma la mia classe base è dichiarata come class B(object):. Ricevo questo errore a causa dell'utilizzo @mock.patch('module.B', autospec=B)appena prima del mio caso di test. Qualche idea su come risolvere questo problema?
MikeyE,

154

Inoltre, se non è possibile modificare la classe B, è possibile correggere l'errore utilizzando l'ereditarietà multipla.

class B:
    def meth(self, arg):
        print arg

class C(B, object):
    def meth(self, arg):
        super(C, self).meth(arg)

print C().meth(1)

16
Non ho potuto fare a meno di lasciare un commento, questo dovrebbe essere accettato come risposta "standard".
workplaylifecycle

9
Per i futuri googler bloccati su Python 2.6: questa è la risposta che probabilmente vorresti! Quando non è possibile modificare la classe di base (ad esempio, si sta eseguendo la sottoclasse di una classe di libreria standard), questa modifica alla propria classe risolve super ().
coredumperror,

Ha funzionato bene per me, qualcuno può spiegare come funziona?
sottoprogramma

@subro, questo rende la tua classe una classe di "nuovo stile" (dove l'oggetto di classe è di tipo type) pur continuando a sottoclassare una classe di "vecchio stile" (il cui oggetto di classe è di tipo classobj). super()funziona con classi di nuovo stile ma non con classi di vecchio stile.
MarSoft,

risposta perfetta!
Tom,

18

Se la versione di Python è 3.X, va bene.

Penso che la tua versione di Python sia 2.X, il super funzionerebbe quando si aggiunge questo codice

__metaclass__ = type

quindi il codice è

__metaclass__ = type
class B:
    def meth(self, arg):
        print arg
class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)
print C().meth(1)

4

Ho anche riscontrato il problema pubblicato quando ho usato Python 2.7. Funziona molto bene con Python 3.4

Per farlo funzionare in Python 2.7 ho aggiunto l' __metaclass__ = typeattributo nella parte superiore del mio programma e ha funzionato.

__metaclass__ : Facilita il passaggio da lezioni di vecchio stile e lezioni di nuovo stile.

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.