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


335

다음을 사용 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 ).


3
질문과 답변에 감사드립니다. 왜 2.7이 super.__doc__이전 스타일과 새로운 스타일에 대해 언급하지 않았 는지 궁금합니다 !
켈빈

감사. :) Docstring은 일반적으로 문서의 전체 HTML 버전보다 적은 정보를 포함합니다. super()새로운 스타일의 클래스 (및 객체)에서만 작동 하는 사실 은 HTML 문서 ( docs.python.org/library/functions.html#super )에 언급되어 있습니다.
Eric O Lebigot


이것은 중복되지 않습니다 (업데이트 된 질문 및 허용되는 답변 참조).
Eric O Lebigot

답변:


246

보통은 " 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

(구식 클래스는 유형 이 아니므로 인스턴스 유형이 될 수 없습니다).


11
그리고 이것이 우리가 파이썬 3를 갖는 이유 중 하나입니다.
Steven Rumbalski

2
BTW : (Oldstyle().__class__ is Oldstyle)isTrue
Tino

2
@ 티노 : 실제로, 요점은 객체 ( )가 구식 클래스에서 나온 OldStyle().__class__것인지 테스트하는 방법을 보여주는 것 입니다. 새로운 스타일의 클래스만을 염두에두고 대신 테스트를 해보고 싶을 수도 있습니다 . OldStyle()isinstance(OldStyle(), object)
Eric O Lebigot

27
여전히 2.7.x 에있는 파이썬 표준 라이브러리의 양 에서 상속받지 않아서 object프록시에 의해 망쳐 놓는 것은 터무니 없습니다 .
Nick Bastin

2
@NickBastin-우연의 일치가 아닙니다. 모든 사람을 파이썬 3으로 밀어 넣기위한 것입니다. "모든 것이 이미 괜찮습니다." 그러나주의해야 할 점은 미끼와 스위치 일뿐입니다.
Tomasz Gandor

204

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 = []

8
나를 위해, 나는 이것을해야했습니다 : HTMLParser .__ init __ (self) 마지막 예제가 효과가 있는지 궁금합니다.
chaimp

1
@EOL 무엇을 의미합니까? jeffp는이 답변에 제공된 코드 selfHTMLParser.__init__()호출 매개 변수 가 없기 때문에 잘못되었다고 지적했습니다 .
Piotr Dobrogost

1
@PiotrDobrogost : 죄송합니다. 제 말은 jeffp의 (좋은) 요점이 아니라 LittleQ의 답변에 관한 것이 었습니다.
Eric O Lebigot

1
@ jeffp 죄송합니다, 오타입니다. 방금 입력 한 것이지만 테스트하지 않았습니다. 수정 주셔서 감사합니다
콜린 수

1
python2.6과 같은 기존 코드에서 작동하는 수정 프로그램에 대한 찬성 투표 2.6
David Reynolds

28

을 사용할 수도 있습니다 class TextParser(HTMLParser, object):. 이 만드는 새로운 스타일의 클래스를, 그리고 사용할 수 있습니다.TextParsersuper()


객체에서 상속을 추가하는 것이 좋은 생각이므로 저의 공감대입니다. (즉,이 답변이 질문의 형식 오류를 이해하는 문제를 해결하지 않습니다 말했다.)
에릭 O Lebigot

23

문제는 조상 이 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

유효한 포인트이지만 이미 이전 답변에 있습니다. 또한 확인하는 대신 type(myclass)중요한 것은 myclass객체에서 상속하는지 여부 (즉, isinstance(myclass, object)참 인지 거짓 인지 여부 )입니다.
Eric O Lebigot

17

당신은 (버전 2.6) 상속 트리를 보면, HTMLParser상속에서 SGMLParser상속에서 어느 ParserBase하지 않습니다 에서 상속을 object. 즉, HTMLParser는 구식 클래스입니다.

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

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

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

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


2
나는 정확한 테스트를해야한다고 생각하지 isinstance(A(), object), 아니 isinstance(A, object), 아니? 후자를 사용하면 여부를 테스트하는 클래스 Aobject문제가 있는지 여부 반면, 인스턴스 의이 A이다 object, 그렇지?
Eric O Lebigot

5
추신 : 가장 좋은 테스트 issubclass(HTMLParser, object)는 False를 반환하는 것 같습니다 .
Eric O Lebigot

5

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

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

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

1
문제 에서이 방법은 이미 언급되었습니다. 문제는 오류 메시지가 생성 된 이유 를 이해 하는 것입니다 (특히 이런 식으로).
Eric O Lebigot

또한 A상태를 저장하는 클래스의 인스턴스를 호출하려는 경우에는이 솔루션이 작동하지 않습니다 .
tashuhka 2016 년

0

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

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.