Python Super

super()는 상속 관계에서 부모 클래스의 메서드를 호출하는 데 사용되는 중요한 도구.

부모 클래스(슈퍼클래스)의 메서드를 호출할 때 사용된다. 주로 자식 클래스에서 부모 클래스의 메서드를 확장하거나 재정의할 때 활용된다.

사용 예제:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        return f"{self.name} makes a sound"

class Dog(Animal):
    def __init__(self, name, breed):
        # 부모 클래스의 __init__ 메서드 호출
        super().__init__(name)
        self.breed = breed
    
    def speak(self):
        # 부모 클래스의 speak 메서드를 확장
        base_sound = super().speak()
        return f"{base_sound} - specifically, a woof!"

# 사용 예시
my_dog = Dog("Rex", "Golden Retriever")
print(my_dog.speak())
# 출력: "Rex makes a sound - specifically, a woof!"

특징

  1. 부모 클래스 참조: super()는 현재 클래스의 부모 클래스를 참조한다.
  2. 메서드 연결: 부모 클래스의 메서드에 접근하여 호출할 수 있게 한다.
  3. 동적 결정: 런타임에 메서드 호출을 결정한다.
  4. MRO(Method Resolution Order) 활용: 다중 상속 시 메서드 해석 순서를 따른다.

장점

  1. 코드 재사용: 부모 클래스의 코드를 재사용하여 중복을 줄인다.
  2. 유연성: 부모 클래스의 구현을 변경해도 자식 클래스에서 수정할 필요가 없다.
  3. 다중 상속 지원: 복잡한 상속 구조에서도 적절한 부모 메서드를 호출할 수 있다.

단점

  1. 복잡성: 다중 상속 시 상속 구조가 복잡해질 수 있다.
  2. 예상치 못한 동작: 상속 계층에 따라 의도하지 않은 메서드가 호출될 수 있다.

주요 사용 방법

  1. super().init(): 부모 클래스의 생성자를 호출한다.
  2. super().method_name(): 부모 클래스의 특정 메서드를 호출한다.

super()의 고급 기능과 특징

다중 상속에서의 활용

super()는 다중 상속 상황에서 메서드 해결 순서(MRO)를 따라 적절한 메서드를 찾아준다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Flying:
    def move(self):
        return "Flying in the air"

class Swimming:
    def move(self):
        return "Swimming in the water"

class Duck(Flying, Swimming):
    def move(self):
        # Flying의 move 메서드 호출
        flying_movement = super().move()
        return f"{flying_movement} and sometimes swimming too"

class DivingDuck(Swimming, Flying):
    def move(self):
        # Swimming의 move 메서드 호출
        swimming_movement = super().move()
        return f"{swimming_movement} and sometimes flying too"

# MRO 확인
print(Duck.mro())
print(DivingDuck.mro())

믹스인 패턴에서의 활용

super()는 믹스인 패턴을 구현할 때 매우 유용하다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class LoggerMixin:
    def log(self, message):
        print(f"[LOG] {message}")
    
    def execute_action(self):
        self.log("Action started")
        result = super().execute_action()
        self.log("Action completed")
        return result

class Service:
    def execute_action(self):
        return "Performing action"

class LoggedService(LoggerMixin, Service):
    pass

# 사용 예시
service = LoggedService()
service.execute_action()

초기화 체인

super()는 복잡한 클래스 계층에서 초기화를 체인처럼 연결할 수 있다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Database:
    def __init__(self, db_name):
        print(f"Initializing database: {db_name}")
        self.db_name = db_name

class Cache:
    def __init__(self, cache_size):
        print(f"Initializing cache: {cache_size}")
        self.cache_size = cache_size

class Application(Database, Cache):
    def __init__(self, db_name, cache_size, app_name):
        print(f"Initializing application: {app_name}")
        super().__init__(db_name)
        Cache.__init__(self, cache_size)
        self.app_name = app_name

# 사용 예시
app = Application("mydb", 1000, "MyApp")

super()의 주의사항과 제약

  1. 초기화 순서 주의

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    class Wrong(Base):
        def __init__(self):
            self.value = 10  # 잘못된 순서
            super().__init__()
    
    class Right(Base):
        def __init__(self):
            super().__init__()  # 올바른 순서
            self.value = 10
    
  2. 다중 상속에서의 복잡성

    1
    2
    
    # 복잡한 다중 상속에서는 MRO를 잘 이해해야 함
    print(ComplexClass.mro())  # MRO 확인이 중요
    
  3. 메서드 시그니처 일관성

    1
    2
    3
    4
    5
    6
    7
    
    class Parent:
        def method(self, x, y):
            pass
    
    class Child(Parent):
        def method(self, x, y):  # 동일한 파라미터 유지
            super().method(x, y)
    

실제 사용 예시와 모범 사례

  1. 메서드 확장하기

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    class BaseValidator:
        def validate(self, data):
            if not data:
                raise ValueError("Data cannot be empty")
            return True
    
    class NumberValidator(BaseValidator):
        def validate(self, data):
            # 기본 검증 수행
            super().validate(data)
            # 추가 검증
            if not isinstance(data, (int, float)):
                raise ValueError("Data must be a number")
            return True
    
  2. 초기화 체인 구성하기

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    class ConfigMixin:
        def __init__(self, config):
            super().__init__()
            self.config = config
    
    class LoggerMixin:
        def __init__(self):
            super().__init__()
            self.logger = self.setup_logger()
    
    class Application(ConfigMixin, LoggerMixin):
        def __init__(self, config):
            super().__init__(config)  # 모든 부모 클래스 초기화
    

참고 및 출처