[python] super ()는 새 스타일 클래스에 대해 “TypeError : classobj가 아니라 type이어야합니다”를 발생시킵니다.

다음을 사용 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를 이해하고 싶습니다.

추신 : Joachim은 새로운 스타일의 인스턴스가되는 것과는 같지 않다고 지적했습니다 object. 나는 그 반대를 여러 번 읽었으므로 혼란 스럽다 (인스턴스 테스트를 기반으로 한 새로운 스타일의 클래스 인스턴스 테스트 object예 : https : //.com/revisions/2655651/3 ).



답변

보통은 ” 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())은 IS instance유형, 않습니다 상속 object. 기본적으로 구식 클래스는 유형의 객체를 생성합니다 instance(신규 스타일 클래스는 유형이 클래스 자체 인 객체를 생성 함). 인스턴스 이유는 아마도 OldStyle()이다 object: 그것 type()에서 상속 object(동급는 않는다는 사실 없습니다 에서 상속 object계산하지 않습니다는 : 이전 스타일의 클래스는 단지 형식의 새로운 객체를 생성 instance). 부분 참조 :https://stackoverflow.com/a/9699961/42973 .

추신 : 새로운 스타일의 클래스와 구식 클래스의 차이점은 다음과 같이 볼 수도 있습니다.

>>> 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):. 이 만드는 새로운 스타일의 클래스를, 그리고 사용할 수 있습니다.TextParsersuper()


답변

문제는 조상 이 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는 구식 클래스입니다.

로 확인에 대해 isinstanceipython에서 빠른 테스트를 수행했습니다.

[1]에서 : 클래스 A :
   ...: 통과하다
   ... :

[2]에서 : isinstance (A, object)
아웃 [2] : 맞음

클래스가 구식 클래스 인 경우에도 여전히의 인스턴스입니다 object.


답변

올바른 방법은 ‘object’에서 상속하지 않는 구식 클래스에서 다음과 같습니다.

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

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


답변

FWIW 그리고 나는 파이썬 전문가가 아니지만 이것으로 끝났다.

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

필요에 따라 구문 분석 결과를 다시 얻었습니다.