super () falla con el error: TypeError "el argumento 1 debe ser type, no classobj" cuando el padre no hereda del objeto


196

Me sale un error que no puedo entender. ¿Alguna pista de lo que está mal con mi código de muestra?

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

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

print C().meth(1)

Obtuve el código de prueba de muestra de la ayuda del método incorporado 'super'.

Aquí está el error:

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

Para su información, aquí está la ayuda (super) de Python:

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
Metanfetamina ?? ¿Es ese un término de programación, o ... ya sabes? Por favor aclarar
Cplusplusplus

3
@Cplusplusplus: probablemente significa Método ;-)
ShadowFlame

Respuestas:


333

Su problema es que la clase B no se declara como una clase de "estilo nuevo". Cámbialo así:

class B(object):

y funcionará

super()y todas las cosas de subclase / superclase solo funcionan con clases de estilo nuevo. Te recomiendo que tengas la costumbre de escribir siempre eso(object) en cualquier definición de clase para asegurarse de que sea una clase de estilo nuevo.

Las clases de estilo antiguo (también conocidas como clases "clásicas") son siempre de tipo classobj; Las clases de nuevo estilo son de tipo type. Es por eso que recibió el mensaje de error que vio:

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

Prueba esto para verlo por ti mismo:

class OldStyle:
    pass

class NewStyle(object):
    pass

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

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

Tenga en cuenta que en Python 3.x, todas las clases son de estilo nuevo. Todavía puede usar la sintaxis de las clases de estilo antiguo, pero obtiene una clase de estilo nuevo. Entonces, en Python 3.x no tendrás este problema.


interesante, encontré este problema exacto al ejecutar bottle.py ( bottlepy.org ) que arroja un error similar (TypeError: debe ser type, no classobj) ejecutándose en Py27 pero no en Py33.
bootload

En Python 3.x, no hay más clases de "estilo antiguo". El código que usa la declaración de "estilo antiguo" todavía declara una clase de "estilo nuevo", por lo que este error no puede ocurrir en Python 3.x.
steveha

1
Si la clase B no está disponible para editar, debe editar la clase A para no intentar usarla super(); Se debe hacer que la clase A funcione con una clase de "estilo antiguo", y posiblemente la mejor manera de hacerlo sería hacer que la clase A sea en sí misma una clase de "estilo antiguo". Por supuesto, recomiendo simplemente actualizar todo su programa para que se ejecute en Python 3.x, para que todas las clases tengan un nuevo estilo sin importar lo que haga; Si esa opción está disponible, es la mejor opción.
steveha

Tengo el mismo problema, pero mi clase base se declara como class B(object):. Recibo este error debido al uso @mock.patch('module.B', autospec=B)justo antes de mi caso de prueba. ¿Alguna idea sobre como arreglar esto?
MikeyE

154

Además, si no puede cambiar la clase B, puede corregir el error utilizando la herencia múltiple.

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
No pude evitar dejar un comentario, este debería ser aceptado como respuesta "estándar".
workplaylifecycle

9
Para futuros googlers atascados en Python 2.6: ¡esta es la respuesta que probablemente quieras! Cuando no puede cambiar la clase base (por ejemplo, está subclasificando una clase de biblioteca estándar), este cambio en su propia clase corrige super ().
coredumperror

A mí me funcionó bien. ¿Alguien puede explicar cómo funciona?
subro

@subro, esto hace que su clase sea una clase de "estilo nuevo" (donde el objeto de clase es de tipo type) mientras sigue subclasificando una clase de "estilo antiguo" (cuyo objeto de clase es de tipo classobj). super()funciona con clases de estilo nuevo pero no con clases de estilo antiguo.
MarSoft

¡Respuesta perfecta!
Tom

18

Si la versión de Python es 3.X, está bien.

Creo que su versión de Python es 2.X, el super funcionaría al agregar este código

__metaclass__ = type

entonces el código es

__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

También me enfrenté al problema publicado cuando usé Python 2.7. Funciona muy bien con Python 3.4.

Para que funcione en Python 2.7, he agregado el __metaclass__ = type atributo en la parte superior de mi programa y funcionó.

__metaclass__ : Facilita la transición de las clases de estilo antiguo y las clases de estilo nuevo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.