super () вызывает "TypeError: должен быть типом, а не classobj" для класса нового стиля

python superclass super typeerror

134065 просмотра

7 ответа

Следующее использование 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 ).

Автор: Eric O Lebigot Источник Размещён: 12.11.2019 09:10

Ответы (7)


244 плюса

Решение

Хорошо, это обычно " 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__есть 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

(классы старого стиля не являются типами, поэтому они не могут быть типом своих экземпляров).

Автор: Eric O Lebigot Размещён: 15.03.2012 12:31

198 плюса

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 = []
Автор: Colin Su Размещён: 14.03.2012 09:07

28 плюса

Вы также можете использовать class TextParser(HTMLParser, object):. Это делает класс TextParserв новом стиле и super()может использоваться.

Автор: Valentin Lorentz Размещён: 04.08.2012 04:01

22 плюса

Проблема в том, что 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
Автор: user2070206 Размещён: 17.10.2015 09:34

17 плюса

Если вы посмотрите на дерево наследования (в версии 2.6), HTMLParserнаследует, от SGMLParserчего наследует, от ParserBaseкоторого не наследует object. Т.е. HTMLParser - это класс в старом стиле.

Что isinstanceкасается вашей проверки , я сделал быстрый тест в ipython:

В [1]: класс А:
   ...: проходят
   ...: 

В [2]: isinstance (A, объект)
Out [2]: True

Даже если класс является классом старого стиля, он все еще является экземпляром object.

Автор: Some programmer dude Размещён: 14.03.2012 09:04

5 плюса

правильный способ сделать это будет следующим в классах старого стиля, которые не наследуются от «объекта»

class A:
    def foo(self):
        return "Hi there"

class B(A):
    def foo(self, name):
        return A.foo(self) + name
Автор: Jacob Abraham Размещён: 18.02.2014 12:30

0 плюса

FWIW и хотя я не гуру Python, я получил с этим

>>> 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
(...)

Просто вернул мне результаты разбора по мере необходимости.

Автор: qwerty_so Размещён: 26.10.2018 03:03
Вопросы из категории :
32x32