python class에서 'super()'의 개념에 대한 정리
python의 class는 상위 class를 상속받을 수 있는데, 상속을 받게되면 하위 클래스는 상위 클래스의 instance와 method의 정보를 물려받게 된다.
예를 들어, 다음과 같은 class A, B를 선언했다고 할때,
class A:
def __init__(self):
self.a = 10
def get_a(self):
return self.a
class B(A):
def __init__(self):
self.b = 20
def get_b(self):
return self.b
B가 A를 상속받고자 한다면, 클래스의 이름 옆에 상속받고자 하는 상위 클래스(A)를 class의 인자로 넣어줌으로써 상속을 받을 수 있다. `class Child(Parent1, Parent2 ...)`
위 상태에서는 B가 A를 상속받고 있기 때문에 b라는 B의 instance가 생성될때, b는 A의 전체 속성을 가지고 생성되게 된다.
그렇다면, b는 A의 정보를 모두 가지고 있으니
b = B()
print(b.get_b())
print(b.get_a())
위 코드를 실행하면,
20
10
의 결과가 나올까? 정답은 아니다.
실제로 동일한 코드를 작성해서 실행하면, `b.get_b()`는 20이 출력되지만, `b.get_a()`는 에러가 발생한다.
그 이유는 Overriding에 있는데, 두 클래스를 선언할때, 각 클래스는 모두 `__init__(self)`이라는 method를 공통적으로 보유하고 있다.
B는 A로 부터 `__init__(self)` 메소드를 상속받았는데, B에서 `__init__` 메소드를 다시 선언하면서 A에서 받은 메소드가 B의 메소드로 Override되어 B의 `__init__`에 대한 정보만 갖게 되는 것이다.
그렇다면, A의 `__init__`과 B의 `__init__`을 모두 살릴 수 있는 방법은 없을까?
super()
이를 해결하기 위한 방법이 `super()`함수를 사용하는 것이다.
class A:
def __init__(self):
self.a = 10
def get_a(self):
return self.a
class B(A):
def __init__(self):
super().__init__() # super(B, self).__init__()
self.b = 20
def get_b(self):
return self.b
맨 처음의 코드를 위의 코드로 수정하면, `super().__init__()`함수를 실행함으로써, A클래스에 존재하는 `__init__` 메소드를 실행시키면서 `self.a`에 대한 속성을 B에서 가질 수 있게 되는 것이다.
따라서, 위 코드에서 B 클래스는 `self.a`, `self.b` 두 개의 attribute를 갖게 된다.
더 나아가, `super()`라는 함수는 '부모 클래스에서 존재하는 속성을 가져온다.`라는 의미의 동작을 하기 때문에,
class A:
def __init__(self):
self.a = 10
def get_a(self):
return self.a
def get_a_2(self):
self.a = 20
class B(A):
def __init__(self):
super().get_a_2() # super(B, self).get_a_2() = B의 부모 클래스(A)에 존재하는 'get_a_2()' 실행
self.b = 20
def get_b(self):
return self.b
b = B()
print(b.a)
위의 코드를 실행하게 되면, 이전의 코드와 달리, 20이 출력되는 것을 확인할 수 있을 것이다.
정리
- 따라서, `super()`의 역할은 인자로 받은 class의 부모 클래스에 존재하는 attribute를 가져오기 위함.
- 예를 들어, `class Child(Parent)`로 선언된 경우에, Parent의 속성을 Child에서 불러와 사용하고 싶다면,
`super().something` or `super(Child, self).something`으로 사용할 수 있음.
- 예를 들어, `class Child(Parent)`로 선언된 경우에, Parent의 속성을 Child에서 불러와 사용하고 싶다면,
- 하지만, 항상 바로 위의 Parent 클래스에 대해서만 `super()`를 사용할 수 있는 것은 아님.
class A:
def __init__(self):
self.a = 10
class B(A):
def __init__(self):
self.b = 20
class C(B):
def __init__(self):
super(B, self).__init__() # super의 인자로 C대신 B를 사용
self.c = 30
c = C()
print(c.a) # 10
print(c.b) # Error
print(c.c) # 30
`super(C,self)`대신 `super(B, self)`를 사용함으로써, B의 Parent(A)의 `__init__()` method를 실행
따라서, `c.b`는 C의 `__init__()`의 override로 인해서 없고, `c.a`, `c.c`만 존재함
- 더 나아가, 상속 관계로 연결되지 않은 class간에는 `super()`의 인자로 사용이 불가함.