class MyBaseClass:
def __init__(self, value):
self.value = value
class MyChildClass(MyBaseClass):
def __init__(self):
MyBaseClass.__init__(self, 5) # << 부모 클래스의 __init__ 메서드 호출
다중 상속 : 두 개 이상의 부모 클래스를 상속하는 경우
모든 하위 클래스에서 __init__호출의 순서가 정해져 있지 않음
class MyBaseClass:
def __init__(self, value):
self.value = value
class TimesTwo:
def __init__(self):
self.value *= 2
class PlusFive:
def __init__(self):
self.value += 5
###########################################################
class OneWay(MyBaseClass, TimesTwo, PlusFive):
def __init__(self, value):
MyBaseClass.__init__(self, value)
TimesTwo.__init__(self)
PlusFive.__init__(self)
class AnotherWay(MyBaseClass, PlusFive, TimesTwo):
def __init__(self, value):
MyBaseClass.__init__(self, value)
TimesTwo.__init__(self)
PlusFive.__init__(self)
foo = OneWay(5)
print('첫 번째 부모 클래스 순서에 따른 값은 (5 * 2) + 5 =', foo.value)
# 첫 번째 부모 클래스 순서에 따른 값은 (5 * 2) + 5 = 15
bar = AnotherWay(5)
print('두 번째 부모 클래스 순서에 따른 값은', foo.value)
# 두 번째 부모 클래스 순서에 따른 값은 (5 * 2) + 5 = 15
클래스 정의에서 부모 클래스를 나열한 순서와 부모 클래스의 생성자를 호출하는 순서가 일치하지 않음.
다이아몬드 상속 : 같은 조상을 가지는 두 클래스를 부모 클래스로 상속하는 경우
class MyBaseClass:
def __init__(self, value):
self.value = value
class TimesSeven(MyBaseClass):
def __init__(self, value):
MyBaseClass.__init__(self, value)
self.value *= 7
class PlusNine(MyBaseClass):
def __init__(self, value):
MyBaseClass.__init__(self, value)
self.value += 9
class ThisWay(TimesSeven, PlusNine):
def __init__(self, value):
TimesSeven.__init__(self, value)
PlusNine.__init__(self, value)
foo = ThisWay(5)
print('(5 * 7) + 9 = 44가 나와야 하지만 실제로는', foo.value)
# (5 * 7) + 9 = 44가 나와야 하지만 실제로는 14
TimesSeven.__init__ 생성자에서 수행한 계산은 무시됨.
참고 > C3 선형화 알고리즘 사용 (추후 공부)
class TimesSevenCorrect(MyBaseClass):
def __init__(self, value):
super().__init__(value)
self.value *= 7
class PlusNineCorrect(MyBaseClass):
def __init__(self, value):
super().__init__(value)
self.value += 9
class GoodWay(TimesSevenCorrect, PlusNineCorrect):
def __init__(self, value):
super().__init__(value)
foo = GoodWay(5)
print('7 * (5 + 9) = 98이 나와야 하고 실제로도', foo.value)
# 7 * (5 + 9) = 98이 나와야 하고 실제로도 98
조상 클래스, BaseClass.__init__이 단 한 번만 호출되어 의도한대로 코드가 동작
하지만,
class GoodWay(TimesSevenCorrect, PlusNineCorrect)
라는 부분을 보면 정의부에 TimesSevenCorrect가 먼저 나왔고 PlusNineCorrect가 나중에 나왔으니 (5*7)+9 가 되어야 하는 거 아닌가? 라는 의문이 들 수 있다.
이에 대한 대답은 다음과 같다.
mro_str = '\n'.join(repr(cls) for cls in GoodWay.mro())
>>>
<class '__main__.GoodWay'> # 4
<class '__main__.TimesSevenCorrect'> # 3
<class '__main__.PlusNineCorrect'> # 2
<class '__main__.MyBaseClass'> # 1
<class 'object'>
super().__init__ 호출은 다중 상속을 튼튼하게 해주며, 하위 클래스에서 MyBaseClass.__init__을 직접 호출하는 것보다 유지 보수를 더 편하게 함
super 함수에 두 가지 파라미터를 넘길 수 있다. 첫 번째 파라미터는 접근하고 싶은 MRO 뷰를 제공할 부모 타입이고, 두 번째 파라미터는 첫 번째 파라미터로 지정한 타입의 MRO 뷰에 접근할 때 사용할 인스턴스이다.
하지만 object 인스턴스를 초기화할 때는 두 파라미터를 지정할 필요가 없다. 아무 인자도 지정하지 않고 super를 호출하면, 파이썬 컴파일러가 자동으로 올바른 파라미터 (__class__와 self)를 넣어준다.