super() plantea "TypeError: debe ser type, no classobj" para la clase de estilo nuevo
El siguiente uso de super()
genera un error tipográfico: ¿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() plantea TypeError, donde el error se explica por el hecho de que la clase user no es una clase de estilo nuevo. Sin embargo, la clase anterior es una clase de estilo nuevo, ya que hereda de object
:
>>> isinstance(HTMLParser(), object)
True
¿Qué me estoy perdiendo? ¿Cómo puedo usar super()
, aquí?
Usar HTMLParser.__init__(self)
en 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 nuevo estilo no es equivalente a ser un object
. Leí lo contrario muchas veces, de ahí mi confusión (ejemplo de prueba de instancia de clase de nuevo estilo basado en object
prueba de instancia: https://stackoverflow.com/revisions/2655651/3).
6 answers
Bien, es lo habitual "super()
no se puede usar con una clase de estilo antiguo".
Sin embargo, el punto importante es que la prueba correcta para "¿es este un nuevo estilo instancia (es decir, objeto)?"es
>>> class OldStyle: pass
>>> instance = OldStyle()
>>> issubclass(instance.__class__, object)
False
Y no (como en la pregunta):
>>> isinstance(instance, object)
True
Para clases , la prueba correcta "es una 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 los tipos son distintos. Aquí, OldStyle().__class__
es OldStyle
, que no hereda de object
, mientras que type(OldStyle())
es el tipo instance
, que hereda de 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 propia clase). Esta es probablemente la razón por la que la instancia OldStyle()
es un object
: su type()
hereda de object
(el hecho de que su clase no hereda no de object
no cuenta: las clases de estilo antiguo construir nuevos objetos de tipo instance
). Referencia parcial: https://stackoverflow.com/a/9699961/42973.
PD: La diferencia entre una clase de estilo nuevo 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 son no tipos, por lo que no pueden ser el tipo de sus instancias).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:36
Super() solo se puede usar en las clases de estilo nuevo, lo que significa que la clase raíz necesita heredar de la clase 'object'.
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 llame al método init del padre directamente, de esta manera:
class TextParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.all_data = []
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-27 03:42:58
También puedes usar class TextParser(HTMLParser, object):
. Esto hace TextParser
una clase de nuevo estilo, y super()
se puede usar.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-11 06:41:55
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
Al examinar más de cerca uno encuentra:
>>> type(myclass)
classobj
Pero:
>>> class newstyle(object): pass
>>> type(newstyle)
type
Así que la solución a su problema sería heredar de object así como de HTMLParser. Pero asegúrese de que object sea el último en las clases MRO:
>>> class myclass(oldstyle, object):
... def __init__(self): super(myclass, self).__init__()
>>> myclass().os
True
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-30 20:18:35
Si se mira el árbol de herencia (en la versión 2.6), HTMLParser
hereda de SGMLParser
que hereda de ParserBase
que no hereda de object
. Es decir, HTMLParser es una clase de estilo antiguo.
Acerca de su comprobació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 de estilo antiguo, sigue siendo una instancia de object
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-14 09:04:56
La forma correcta de hacerlo será la siguiente en las clases de estilo antiguo que no heredan de'object'
class A:
def foo(self):
return "Hi there"
class B(A):
def foo(self, name):
return A.foo(self) + name
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-20 10:31:39