__init __ ()가 부모 클래스의 __init __ ()을 호출해야합니까?


132

나는 Objective-C 에서이 구성을 얻었습니다.

- (void)init {
    if (self = [super init]) {
        // init class
    }
    return self;
}

파이썬은 부모 클래스의 구현을 호출해야합니까 __init__?

class NewClass(SomeOtherClass):
    def __init__(self):
        SomeOtherClass.__init__(self)
        # init class

이것은에도 참 / 거짓의인가 __new__()__del__()?

편집 : 매우 유사한 질문이 있습니다 : 파이썬의 상속과 재정 __init__


코드를 크게 변경했습니다. 나는 원본 object이 오타 라는 것을 이해할 수 있습니다 . 그러나 지금 당신 super은 당신의 질문의 제목 조차 언급 하지 않습니다 .
SilentGhost

방금 super가 부모 클래스의 이름으로 사용되었다고 생각했습니다. 나는 아무도 그 기능을 생각할 것이라고 생각하지 않았다. 오해에 대해 죄송합니다.
Georg Schölly

답변:


67

파이썬에서 슈퍼 클래스를 호출하는 __init__것은 선택 사항입니다. 호출하면 super식별자 사용 여부 또는 수퍼 클래스 이름을 명시 적으로 지정할지 여부도 선택 사항입니다 .

object.__init__(self)

객체의 경우, super 메소드가 비어 있으므로 super 메소드를 호출 할 필요는 없습니다. 동일합니다 __del__.

반면에, for __new__는 실제로 다른 메소드를 명시 적으로 리턴하지 않는 한 실제로 super 메소드를 호출하고 해당 리턴을 새로 작성된 오브젝트로 사용해야합니다.


그래서 super의 구현을 호출하는 규칙이 없습니까?
Georg Schölly

5
구식 클래스에서는 수퍼 클래스에 실제로 init가 정의되어 있는 경우 에만 수퍼 init를 호출 할 수있었습니다 (종종 그렇지 않은 경우). 따라서 사람들은 일반적으로 슈퍼 메쏘드를 원칙에서 벗어나기보다는 슈퍼 ​​메쏘드 호출에 대해 생각합니다.
Martin v. Löwis

1
파이썬의 구문이 ~처럼 간단하다면 [super init]더 일반적 일 것입니다. 단지 추측적인 생각; 파이썬 2.x의 슈퍼 구문은 약간 어색합니다.
u0b34a0f6ae

: 여기에 흥미로운 (그리고 아마도 모순) 예 것으로 보인다 bytes.com/topic/python/answers/... 초기화
mlvljr

"선택적"이라는 점에서 호출 할 필요는 없지만 호출하지 않아도 자동으로 호출되지는 않습니다.
McKay

140

__init__현재 클래스에서 수행되는 작업 외에도 수퍼에서 수행 해야 할 작업이 필요한 경우 __init__,자동으로 수행되지 않으므로 직접 호출해야합니다. 그러나 super에서 아무것도 필요하지 않으면 __init__,전화 할 필요가 없습니다. 예:

>>> class C(object):
        def __init__(self):
            self.b = 1


>>> class D(C):
        def __init__(self):
            super().__init__() # in Python 2 use super(D, self).__init__()
            self.a = 1


>>> class E(C):
        def __init__(self):
            self.a = 1


>>> d = D()
>>> d.a
1
>>> d.b  # This works because of the call to super's init
1
>>> e = E()
>>> e.a
1
>>> e.b  # This is going to fail since nothing in E initializes b...
Traceback (most recent call last):
  File "<pyshell#70>", line 1, in <module>
    e.b  # This is going to fail since nothing in E initializes b...
AttributeError: 'E' object has no attribute 'b'

__del__같은 방법입니다 (그러나 __del__마무리 에 의존하는 것에주의하십시오 -대신 with 문을 통해 수행하는 것을 고려하십시오).

나는 거의 __new__. 모든 초기화를 사용 하지 않는다 .__init__.


3
클래스 D (C)의 정의는 다음과 같이 수정되어야합니다.super(D,self).__init__()
eyquem

11
super () .__ init __ ()는 Python 3에서만 작동합니다. Python 2에서는 super (D, self) .__ init __ () 필요
Jacinda

"super의 init 에서 무언가가 필요하다면 ..."-이것은 당신 / 서브 클래스에 "무언가"가 필요한지의 여부가 아니라, 기본 클래스가 유효하기 위해 무언가가 필요한지의 여부 때문에 매우 문제가되는 진술입니다 기본 클래스 인스턴스 및 올바르게 작동합니다. 파생 클래스의 구현 자로서, 기본 클래스 내부는 알 수 없거나 알아야 할 사항이며, 내부 또는 내부를 모두 기록했거나 문서화했기 때문에 작성하더라도베이스의 디자인은 잘못 작성되어 향후 변경 될 수 있습니다. 파생 클래스. 따라서 항상 기본 클래스가 완전히 초기화되었는지 확인하십시오.
Nick

105

Anon의 답변에서 :
" __init__현재 수업에서 수행되고있는 것 외에 수퍼로부터 무언가를해야한다면 __init__, 자동으로 일어나지 않기 때문에 직접 호출해야합니다."

그는 믿어지지 않습니다 : 그는 상속의 원칙과 정확히 반대되는 말을하고 있습니다.


그것은 것이 아니다 "슈퍼의에서 뭔가 __init__ (...) 자동으로 일어나지 않을 것입니다" 기본 클래스 '가 있기 때문에 자동으로 일어날 것입니다,하지만 일이 발생하지 __init__파생-제공자 라이선스 계약의 정의에 의해 오버라이드 (override)한다__init__

그러면 파생 된 클래스를 정의하는 이유 __init__는 누군가가 상속에 의존 할 때 목표를 무시하기 때문입니다.

그것은 기본 클래스에서 수행되지 않은 것을 정의해야하기 때문이며 __init__, 그것을 얻을 수있는 유일한 가능성은 실행을 파생 클래스의 __init__함수 에 넣는 것입니다.
다시 말해, 이 클래스__init____init__ 가 재정의되지 않은 경우 기본 클래스 에서 자동으로 수행되는 것 외에도 기본 클래스에 무언가가 필요합니다 .
반대가 아닙니다.


그러면 문제는 기본 클래스에있는 원하는 명령 __init__이 인스턴스화 시점에 더 이상 활성화되지 않는다는 것입니다. 이 비활성화를 상쇄하기 위해서는 특별한 것이 필요하다 :베이스 클래스에 의해 수행되는 초기화를 추가하지 말고 유지__init__ 하기 위해 베이스 클래스를 명시 적으로 호출한다 . 그것이 공식 문서에서 정확히 말한 것입니다.__init__

파생 클래스의 재정의 메서드는 실제로 같은 이름 의 기본 클래스 메서드단순히 대체하기보다는 확장하는 것이 좋습니다 . 기본 클래스 메소드를 직접 호출하는 간단한 방법이 있습니다. BaseClassName.methodname (self, arguments)을 호출하십시오.
http://docs.python.org/tutorial/classes.html#inheritance

그게 다 이야기입니다 :

  • 목표가 기본 클래스에 의해 수행되는 초기화를 유지하는 것, 즉 순수한 상속, 특별한 것은 필요하지 않으며 __init__파생 클래스에서 함수 를 정의하지 않아야합니다.

  • 목표가 기본 클래스에 의해 수행 된 초기화를 대체하는 __init__경우 파생 클래스에 정의되어야합니다.

  • 기본 클래스에 의해 수행 된 초기화에 프로세스를 추가하는 것이 목표 인 경우, 기본 클래스에 __init__ 대한 명시 적 호출을 포함하여 파생 클래스를 정의해야합니다.__init__


Anon의 포스트에서 놀랍게 생각하는 것은 그가 상속 이론의 반대를 표현할뿐만 아니라 머리카락을 돌리지 않고 upvoted하는 5 명의 사람들이 지나갔으며, 2 년 안에 아무도 반응하지 않았다는 것입니다. 흥미로운 주제를 비교적 자주 읽어야하는 스레드


1
이 게시물이 공개 될 것이라고 확신했습니다. 이유에 대한 설명이 많지 않은 것 같습니다. 이해할 수없는 것으로 보이는 텍스트를 분석하는 것보다 다운 보트가 더 쉽습니다. 나는 아논의 글을 이해하기 위해 오랜 시간을 보냈다. 상속에 대해 아는 사람에게는 거의 올바른 것으로 해석 될 수 있습니다. 하지만 일반적으로 바위 물로 명확로하지 상속, 주제에 대한 불안 정한 개념을 가진 사람이 읽을 때 confusioning 찾을
eyquem

2
"이 게시물이 공표 될 것이라고 확신했습니다 ..."주요 문제는 당신이 파티에 약간 늦어서 대부분의 사람들이 처음 몇 가지 답변을 읽지 못할 수도 있다는 것입니다.
그건

좋은 대답입니다.
Trilarion 2014 년

3
아론에게서 인용 한 문장에서 "추가로"중요한 단어를 놓쳤습니다. 아론의 진술은 완전히 정확하며, 당신이 말하는 것과 일치합니다.
GreenAsJade

1
이것은 파이썬의 디자인 선택이 이해하기 쉬운 첫 번째 설명입니다.
Joseph Garvin

20

편집 : (코드 변경 후)
부모님 __init__(또는 다른 기능) 을 호출 해야하는지 여부를 알려주는 방법은 없습니다 . 상속은 분명히 그러한 요청없이 작동합니다. 그것은 모두 코드의 논리에 달려 있습니다. 예를 들어, 모든 __init__것이 부모 클래스에서 끝나면 자식 클래스를 __init__모두 건너 뛸 수 있습니다 .

다음 예제를 고려하십시오.

>>> class A:
    def __init__(self, val):
        self.a = val


>>> class B(A):
    pass

>>> class C(A):
    def __init__(self, val):
        A.__init__(self, val)
        self.a += val


>>> A(4).a
4
>>> B(5).a
5
>>> C(6).a
12

예제에서 수퍼 호출을 제거했습니다. 부모 클래스의 init 구현을 호출 해야하는지 여부를 알고 싶었습니다 .
Georg Schölly

그런 다음 제목을 편집 할 수 있습니다. 하지만 내 대답은 여전히 ​​유효합니다.
SilentGhost

5

어렵고 빠른 규칙은 없습니다. 클래스 문서는 서브 클래스가 수퍼 클래스 메소드를 호출해야하는지 여부를 표시해야합니다. 때로는 수퍼 클래스 동작을 완전히 바꾸고 다른 경우에는 수퍼 클래스 호출 전후에 자신의 코드를 호출해야합니다.

업데이트 : 동일한 기본 로직이 모든 메소드 호출에 적용됩니다. 생성자는 병렬 생성자 (예 : 데이터베이스 할당과 같은 자원 할당)와 같이 특수한 고려 사항 (동작을 결정하는 상태를 설정하는 경우가 많음)과 소멸자를 고려해야합니다. 그러나 render()위젯 의 방법 에도 동일하게 적용될 수 있습니다 .

추가 업데이트 : OPP 란 무엇입니까? 당신은 OOP를 의미합니까? 아니오-서브 클래스는 종종 수퍼 클래스 디자인에 대해 알아야 합니다 . 내부 구현 세부 사항이 아니라 슈퍼 클래스가 클라이언트와 맺은 기본 계약 (클래스 사용). 이것은 어떠한 방식으로도 OOP 원칙을 위반하지 않습니다. 그렇기 때문에 protected일반적으로 OOP에서 유효한 개념입니다 (물론 파이썬에서는 그렇지 않습니다).


때로는 슈퍼 클래스 호출 전에 자신의 코드를 호출하고 싶을 수도 있다고 말했다. 이를 위해서는 OPP를 위반하는 부모 클래스의 구현에 대한 지식이 필요합니다.
Georg Schölly

4

IMO, 전화해야합니다. 수퍼 클래스가 object인 경우 , 그렇지 않아야하지만 다른 경우에는 호출하지 않는 것이 예외적이라고 생각합니다. 이미 다른 사람들이 대답했듯이 클래스가 __init__초기화 할 (추가) 내부 상태가없는 경우와 같이 클래스를 재정의 할 필요가없는 경우 매우 편리합니다 .


2

그렇습니다 __init__. 좋은 코딩 연습으로 항상 기본 클래스를 명시 적으로 호출해야합니다 . 잊어 버리면 미묘한 문제 나 런타임 오류가 발생할 수 있습니다. __init__매개 변수를 사용하지 않더라도 마찬가지 입니다. 이것은 컴파일러가 암시 적으로 기본 클래스 생성자를 호출하는 다른 언어와 다릅니다. 파이썬은 그렇게하지 않습니다!

항상 기본 클래스를 호출하는 주된 이유 _init__는 기본 클래스가 일반적으로 멤버 변수를 작성하여 기본값으로 초기화 할 수 있기 때문입니다. 따라서 기본 클래스 init를 호출하지 않으면 해당 코드 중 어느 것도 실행되지 않으며 멤버 변수가없는 기본 클래스로 끝납니다.

:

class Base:
  def __init__(self):
    print('base init')

class Derived1(Base):
  def __init__(self):
    print('derived1 init')

class Derived2(Base):
  def __init__(self):
    super(Derived2, self).__init__()
    print('derived2 init')

print('Creating Derived1...')
d1 = Derived1()
print('Creating Derived2...')
d2 = Derived2()

인쇄합니다 ..

Creating Derived1...
derived1 init
Creating Derived2...
base init
derived2 init

이 코드를 실행하십시오 .

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