method python superclass super typeerror

method - super on python



super() genera "TypeError: debe ser type, no classobj" para la clase de nuevo estilo (7)

El problema es que super necesita un object como ancestro:

>>> class oldstyle: ... def __init__(self): self.os = True >>> class myclass(oldstyle): ... def __init__(self): super(myclass, self).__init__() >>> myclass() TypeError: must be type, not classobj

En un examen más detallado se encuentra:

>>> type(myclass) classobj

Pero:

>>> class newstyle(object): pass >>> type(newstyle) type

Por lo tanto, la solución a su problema sería heredar tanto del objeto como de HTMLParser. Pero asegúrese de que el objeto llegue el último en las clases MRO:

>>> class myclass(oldstyle, object): ... def __init__(self): super(myclass, self).__init__() >>> myclass().os True

El siguiente uso de super() genera un TypeError: ¿por qué?

>>> from HTMLParser import HTMLParser >>> class TextParser(HTMLParser): ... def __init__(self): ... super(TextParser, self).__init__() ... self.all_data = [] ... >>> TextParser() (...) TypeError: must be type, not classobj

Hay una pregunta similar en StackOverflow: Python super () genera TypeError , donde el error se explica por el hecho de que la clase de usuario no es una clase de nuevo estilo. Sin embargo, la clase anterior es una clase de nuevo estilo, ya que hereda del object :

>>> isinstance(HTMLParser(), object) True

¿Qué me estoy perdiendo? ¿Cómo puedo usar super() , aquí?

Usar HTMLParser.__init__(self) lugar de super(TextParser, self).__init__() funcionaría, pero me gustaría entender el TypeError.

PS: Joachim señaló que ser una instancia de clase de estilo nuevo no es equivalente a ser un object . Leí el opuesto muchas veces, de ahí mi confusión (ejemplo de prueba de instancia de clase de nuevo estilo basada en prueba de instancia de object : https://stackoverflow.com/revisions/2655651/3 ).


FWIW y, aunque no soy un gurú de Python, he podido resolver esto

>>> class TextParser(HTMLParser): ... def handle_starttag(self, tag, attrs): ... if tag == "b": ... self.all_data.append("bold") ... else: ... self.all_data.append("other") ... ... >>> p = TextParser() >>> p.all_data = [] >>> p.feed(text) >>> print p.all_data (...)

Acabo de recibir los resultados del análisis según sea necesario.


Muy bien, es el habitual " super() no se puede usar con una clase de estilo antiguo".

Sin embargo, el punto importante es que la prueba correcta para "¿es esta una instancia de nuevo estilo (es decir, un objeto)?" es

>>> class OldStyle: pass >>> instance = OldStyle() >>> issubclass(instance.__class__, object) False

Y no (como en la pregunta):

>>> isinstance(instance, object) True

Para las clases , la prueba correcta "es esta clase de nuevo estilo" es:

>>> issubclass(OldStyle, object) # OldStyle is not a new-style class False >>> issubclass(int, object) # int is a new-style class True

El punto crucial es que con las clases de estilo antiguo, la clase de una instancia y su tipo son distintas. Aquí, OldStyle().__class__ es OldStyle , que no hereda del object , mientras que type(OldStyle()) es el tipo de instance , que hereda del object . Básicamente, una clase de estilo antiguo simplemente crea objetos de tipo instance (mientras que una clase de estilo nuevo crea objetos cuyo tipo es la clase en sí). Probablemente esta sea la razón por la que OldStyle() es un object : su type() hereda del object (el hecho de que su clase no hereda del object no cuenta: las clases de estilo antiguo simplemente construyen nuevos objetos de tipo instance ). Referencia parcial: https://.com/a/9699961/42973 .

PD: La diferencia entre una clase de nuevo estilo y una de estilo antiguo también se puede ver con:

>>> type(OldStyle) # OldStyle creates objects but is not itself a type classobj >>> isinstance(OldStyle, type) False >>> type(int) # A new-style class is a type type

(Las clases de estilo antiguo no son tipos, por lo que no pueden ser el tipo de sus instancias).


Si observa el árbol de herencia (en la versión 2.6), HTMLParser hereda de HTMLParser , que hereda de ParserBase que no hereda de object . Es decir, HTMLParser es una clase de estilo antiguo.

Acerca de su verificación con isinstance , hice una prueba rápida en ipython:

In [1]: class A: ...: pass ...: In [2]: isinstance(A, object) Out[2]: True

Incluso si una clase es una clase de estilo antiguo, sigue siendo una instancia de object .


También puede utilizar la class TextParser(HTMLParser, object): Esto hace que TextParser sea ​​una clase de nuevo estilo , y se puede usar super() .


la forma correcta de hacerlo será la siguiente en las clases de estilo antiguo que no heredan de ''objeto''

class A: def foo(self): return "Hi there" class B(A): def foo(self, name): return A.foo(self) + name


super () solo se puede utilizar en las clases de nuevo estilo, lo que significa que la clase raíz necesita heredar de la clase ''objeto''.

Por ejemplo, la clase superior debe ser así:

class SomeClass(object): def __init__(self): ....

no

class SomeClass(): def __init__(self): ....

Entonces, la solución es que se llame directamente al método init del padre, de esta manera:

class TextParser(HTMLParser): def __init__(self): HTMLParser.__init__(self) self.all_data = []