super () вызывает "TypeError: должен быть type, а не classobj" для класса нового стиля
следующее использование super()
поднимает TypeError: почему?
>>> from HTMLParser import HTMLParser
>>> class TextParser(HTMLParser):
... def __init__(self):
... super(TextParser, self).__init__()
... self.all_data = []
...
>>> TextParser()
(...)
TypeError: must be type, not classobj
есть аналогичный вопрос о StackOverflow:Python super () вызывает TypeError, где ошибка объясняется тем, что класс пользователя не является классом нового стиля. Однако класс выше является классом нового стиля, поскольку он наследуется от object
:
>>> isinstance(HTMLParser(), object)
True
что я упустил? Как я могу использовать super()
здесь?
используя HTMLParser.__init__(self)
вместо super(TextParser, self).__init__()
будет работать, но я хотел бы понять ошибку TypeError.
PS: Иоахим указал, что быть экземпляром класса нового стиля не эквивалентно быть object
. Я читал противоположное много раз, поэтому моя путаница (пример теста экземпляра класса нового стиля на основе object
тест экземпляра:https://stackoverflow.com/revisions/2655651/3).
6 ответов
хорошо, это обычный "super()
не может использоваться с классом старого стиля".
однако важным моментом является то, что корректный тест для "это новый стиль экземпляр (т. е. объект)?"это
>>> class OldStyle: pass
>>> instance = OldStyle()
>>> issubclass(instance.__class__, object)
False
, а не (как в вопросе):
>>> isinstance(instance, object)
True
на классы, правильный тест" это класс нового стиля":
>>> issubclass(OldStyle, object) # OldStyle is not a new-style class
False
>>> issubclass(int, object) # int is a new-style class
True
на ключевой момент заключается в том, что с классы старого стиля,класс экземпляра и его тип различны. Вот,OldStyle().__class__
is OldStyle
, который не наследуется от object
, а type(OldStyle())
- это instance
тип, который тут наследовать от object
. В принципе, класс старого стиля просто создает объекты типа instance
(в то время как класс нового стиля создает объекты, тип которых является самим классом). Вероятно, именно поэтому экземпляр OldStyle()
это object
: его type()
наследует от object
(тот факт, что его класс не наследовать от object
не считается: классы старого стиля просто строят новые объекты типа instance
). Частичная ссылка: https://stackoverflow.com/a/9699961/42973.
PS: разница между классом нового стиля и старым стилем также можно увидеть с помощью:
>>> 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
(старого стиля классы не типы, поэтому они не могут быть типа их экземпляры).
super () может использоваться только в классах нового стиля, что означает, что корневой класс должен наследовать от класса "object".
например, верхний класс должен быть таким:
class SomeClass(object):
def __init__(self):
....
не
class SomeClass():
def __init__(self):
....
Итак, решение заключается в том, что вызов родителей init метод напрямую, вот так:
class TextParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.all_data = []
вы также можете использовать class TextParser(HTMLParser, object):
. Это делает TextParser
a новый стиль класс, а super()
можно использовать.
проблема в том, что super
нужен object
как предок:
>>> 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
при ближайшем рассмотрении обнаруживаешь:
>>> type(myclass)
classobj
но:
>>> class newstyle(object): pass
>>> type(newstyle)
type
таким образом, решение вашей проблемы будет наследовать от объекта, а также от HTMLParser. Но убедитесь, что объект идет последним в классах MRO:
>>> class myclass(oldstyle, object):
... def __init__(self): super(myclass, self).__init__()
>>> myclass().os
True
если вы посмотрите на дерево наследования (в версии 2.6), HTMLParser
наследует от SGMLParser
, который наследует от ParserBase
, который не наследует от object
. Т. е. HTMLParser-это класс старого стиля.
о проверке с isinstance
, Я сделал быстрый тест в IPython:
In [1]: class A: ...: pass ...: In [2]: isinstance(A, object) Out[2]: True
даже если класс является классом старого стиля, он по-прежнему является экземпляром object
.
правильный способ сделать будет следующим в классах старого стиля, которые не наследуются от 'object'
class A:
def foo(self):
return "Hi there"
class B(A):
def foo(self, name):
return A.foo(self) + name