본문 바로가기

공부

[Python] class / super()

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`으로 사용할 수 있음.

 

  • 하지만, 항상 바로 위의 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()`의 인자로 사용이 불가함.