
객체 지향 프로그래밍(OOP)을 지원하는 언어 중 파이썬은 강력하면서도 유연한 다중 상속(Multiple Inheritance) 기능을 제공합니다. 하지만 상속 구조가 복잡해질수록 "도대체 어떤 부모 클래스의 메서드가 먼저 실행되는가?"라는 혼란에 빠지기 쉽습니다. 특히 super() 함수는 단순히 '직계 부모'를 호출하는 것이 아니라, 파이썬만의 독특한 규칙을 따릅니다. 이 글에서는 다중 상속 구조에서 발생할 수 있는 죽음의 다이아몬드(Diamond of Death) 문제를 해결하는 super()의 동작 원리와 MRO(Method Resolution Order) 알고리즘을 심도 있게 분석합니다.
## 1. super()는 왜 직계 부모가 아닐까? (C3 Linearization)
흔히 초보 개발자들은 super()가 클래스 정의 시 괄호 안에 적은 바로 위 부모를 호출한다고 생각합니다. 하지만 파이썬의 super()는 MRO(메서드 결정 순서)라는 선형화된 리스트를 따라 다음 순서의 클래스를 호출합니다.
파이썬 3부터는 C3 Linearization 알고리즘을 사용하여 이 순서를 결정합니다. 이 알고리즘은 다음 3가지 원칙을 보장합니다.
- 서브클래스는 부모보다 먼저 나타난다.
- 여러 부모가 있을 경우, 상속 리스트(괄호 안)에 적힌 순서를 유지한다.
- 단일 상속의 단조성(Monotonicity)을 유지한다.
--- ## 2. 단일 상속 vs 다중 상속의 MRO 차이 비교
상속 구조에 따라 super()가 탐색하는 경로의 차이를 표로 정리하였습니다.
| 구분 | 단일 상속 (Single) | 다중 상속 (Multiple) |
|---|---|---|
| 구조 | A -> B | (B, C) -> D |
| 탐색 방식 | 수직적 계층 구조 탐색 | C3 알고리즘에 따른 수평+수직 혼합 탐색 |
| super()의 역할 | 물리적 부모 클래스 호출 | MRO 리스트 상의 차례대로의 '다음' 클래스 호출 |
| 주요 위험 요소 | 없음 | 의도치 않은 부모 메서드 중복 실행 또는 누락 |
--- ## 3. 실전 예제: 다이아몬드 구조 해결 방법
아래는 전형적인 다이아몬드 상속 구조에서 super().__init__()이 어떻게 모든 부모를 단 한 번씩만 방문하는지 보여주는 샘플 코드입니다.
### Sample Example
class Top:
def __init__(self):
print("Top.__init__ 호출")
class Left(Top):
def __init__(self):
print("Left.__init__ 시작")
super().__init__()
print("Left.__init__ 종료")
class Right(Top):
def __init__(self):
print("Right.__init__ 시작")
super().__init__()
print("Right.__init__ 종료")
class Bottom(Left, Right):
def __init__(self):
print("Bottom.__init__ 시작")
super().__init__()
print("Bottom.__init__ 종료")
# 실행 결과 확인
instance = Bottom()
print(f"MRO 순서: {[cls.__name__ for cls in Bottom.mro()]}")
결과 해석: Bottom의 MRO는 [Bottom, Left, Right, Top, object]입니다. Left에서 super().__init__()을 호출할 때, Top이 아닌 Right가 호출되는 점이 핵심입니다. 이는 super()가 현재 클래스의 부모를 찾는 것이 아니라, 인스턴스의 전체 MRO 리스트에서 현재 위치의 다음 항목을 찾기 때문입니다.
--- ## 4. 다중 상속 설계 시 2가지 주의사항
- 협력적 다중 상속(Cooperative Multiple Inheritance): 모든 부모 클래스의 메서드 내부에
super()호출이 포함되어야 체인이 끊기지 않습니다. - 인자 전달의 일관성: 부모 클래스들이 서로 다른 인자를 요구할 경우
**kwargs를 사용하여 유연하게 인자를 전달하는 것이 안전한 해결 방법입니다.
--- ## 5. 결론 및 요약
파이썬에서 super()는 단순한 부모 호출기가 아니라, 복잡한 상속 그래프를 하나의 선으로 펴주는 MRO 내비게이터입니다. 다중 상속을 사용할 때는 반드시 해당 클래스의 .mro() 결과를 확인하여 메서드 호출 순서를 예측해야 예기치 못한 버그를 방지할 수 있습니다.
### 출처 (Sources)
- Python Software Foundation: "The Python 2.3 Method Resolution Order" (C3 알고리즘 공식 문서)
- Fluent Python by Luciano Ramalho: "Inheritance: For Good or For Worse"
- Real Python: "Supercharge Your Classes With Python super()"