<jupyter_start><jupyter_text>super로 부모 클래스를 초기화하자기존에는 자식 클래스에서 부모 클래스의 `__init__` 메서드를 직접 호출하는 방법으로 부모 클래스를 초기화했다.<jupyter_code>class MyBaseClass(object):
    def __init__(self, value):
        self.value = value
        
class MyChildClass(MyBaseClass):
    def __init__(self):
        MyBaseClass.__init__(self, 5)<jupyter_output><empty_output><jupyter_text>간단한 계층 구조에는 잘 동작하지만 많은 경우 제대로 동작하지 못한다.클래스가 다중 상속의 영향을 받는다면 superclass의 `__init__` 메서드를 직접 호출하는 행위는 문제를 일으킬 수 있다.  한 가지 문제는 `__init__`의 호출 순서가 모든 서브클래스에 걸쳐 명시되어 있지 않다는 점이다.인스턴스의 value 필드로 연산을 수행하는 부모 클래스 정의<jupyter_code>class TimesTwo(object):
    def __init__(self):
        self.value *= 2
        
class PlusFive(object):
    def __init__(self):
        self.value += 5<jupyter_output><empty_output><jupyter_text>다음 클래스는 한 가지 순서로 부모 클래스들을 정의한다.<jupyter_code>class OneWay(MyBaseClass, TimesTwo, PlusFive):
    def __init__(self, value):
        MyBaseClass.__init__(self, value)
        TimesTwo.__init__(self)
        PlusFive.__init__(self)<jupyter_output><empty_output><jupyter_text>이 클래스의 인스턴스를 생성하면 부모 클래스의 순서와 일치하는 결과가 만들어진다.<jupyter_code>foo = OneWay(5)
print('First ordering is (5 * 2) + 5 =', foo.value)<jupyter_output>First ordering is (5 * 2) + 5 = 15<jupyter_text>다음과 같은 부모 클래스들을 다른 순서로 정의한 클래스다.<jupyter_code>class AnotherWay(MyBaseClass, PlusFive, TimesTwo):
    def __init__(self, value):
        MyBaseClass.__init__(self, value)
        TimesTwo.__init__(self)
        PlusFive.__init__(self)<jupyter_output><empty_output><jupyter_text>하지만 부모 클래스 생성자를 이전과 같은 순서로 호출한다. 따라서 클래스의 동작은 부모 클래스를 정의한 순서와 일치하지 않는다.<jupyter_code>bar = AnotherWay(5)
print('Second ordering still is', bar.value)<jupyter_output>Second ordering still is 15<jupyter_text>다른 문제는 다이아몬드 상속(`diamond inheritance`)이다.  서브 클래스가 계층 구조에서 같은 superclass를 둔 서로 다른 두 클래스에서 상속받을 때 발생한다.  공통 슈퍼클래스의 `__init__` method를 여러 번 실행하게 해서 예상치 못한 동작을 일으킨다.<jupyter_code>class TimesFive(MyBaseClass):
    def __init__(self, value):
        MyBaseClass.__init__(self, value)
        self.value *= 5
class PlusTwo(MyBaseClass):
    def __init__(self, value):
        MyBaseClass.__init__(self, value)
        self.value += 2
class ThisWay(TimesFive, PlusTwo):
    def __init__(self, value):
        TimesFive.__init__(self, value)
        PlusTwo.__init__(self, value)
foo = ThisWay(5)
print('Should be (5 * 5) + 2 = 27 but is', foo.value)<jupyter_output>Should be (5 * 5) + 2 = 27 but is 7<jupyter_text>결과가 27이 아닌 이유는 `PlusTwo.__init__`를 호출하는 코드가 있어서 `MyBaseClass.__init__`가 두 번째 호출될 때 `self.value`를 다시 5로 리셋한다.Python2.2에서는 이 문제를 해결하려고 super라는 내장 함수를 추가하고 method 해석 순서(`MRO`, Method Resolution Order)를 정의했다.  MRO는 어떤 superclass로부터 초기화하는지를 정한다. 또한 다이아몬드 계층 구조에 있는 공통 superclass를 단 한 번만 실행하게 한다. ```pyclass TimesFiveCorrect(MyBaseClass):    def __init__(self, value):        super(TimesFiveCorrect, self).__init__(value)        self.value *= 5        class PlusTwoCorrect(MyBaseClass):    def __init__(self, value):        super(PlusTwoCorrect, self).__init__(value)        self.value += 2        class GoodWay(TimesFiveCorrect, PlusTwoCorrect):    def __init__(self, value):        super(GoodWay, self).__init__(value)        foo = GoodWay(5)print 'Should be 5 * (5 + 2) = 35 and is', foo.value>>>Should be 5 * (5 + 2) = 35 and is 35```이 순서는 뒤와 같은데 class 에 대해 MRO가 정의하는 순서와 일치한다. 따라서 연산 순서를 변경할 수 없다.```pyfrom pprint import pprintpprint(GoodWay.mro())>>>[,,,,]```GoodWay(5)를 호출 --> `TimesFiveCorrrect.__init__` --> `PlusTwoCorrect.__init__` --> `MyBaseClass.__init__` --> value에 5 할당 --> `PlusTwoCorrect.__init__`는 2를 더해서 7 --> `TimesFiveCorrect.__init__`는 5를 곱해서 value는 35 Python2의 문제점1. 문법이 장황하다. 현재 정의하는 클래스, self 객체, 메서드 이름(보통 `__init__`)과 모든 인수 설정 필요2. super를 호출하면서 현재 클래ㅡㅅ의 이름을 지정해야 함. 클래스의 이름 변경 시 super호출하는 모든 코드 수정 필요 Python3에서는 super를 인수 없이 호출하면 `__class__`와 self를 인수로 넘겨서 호출한 것으로 처리해서 이 문제를 해결한다. Python3에서는 항상 super를 사용해야 한다. super는 명확하고 간결하며 항상 제대로 동작하기 때문이다.<jupyter_code>class Explicit(MyBaseClass):
    def __init__(self, value):
        super(__class__, self).__init__(value * 2)
class Implicit(MyBaseClass):
    def __init__(self, value):
        super().__init__(value * 2)
assert Explicit(10).value == Implicit(10).value<jupyter_output><empty_output>
StarcoderdataJupyterStructuredCleanDedup