본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] 다중 상속의 마법 : super()와 MRO 알고리즘의 2가지 동작 원리 및 해결 방법

by Papa Martino V 2026. 3. 4.
728x90

super()와 MRO 알고리즘
super()와 MRO 알고리즘

 

파이썬의 객체 지향 프로그래밍(OOP)에서 가장 강력하면서도 동시에 가장 혼란스러운 개념 중 하나가 바로 다중 상속(Multiple Inheritance)입니다. 여러 부모 클래스로부터 기능을 물려받을 수 있다는 점은 매력적이지만, 부모 클래스들이 동일한 이름의 메서드를 가지고 있을 때 파이썬이 어떤 순서로 호출 대상을 결정하는지는 단순하지 않습니다. 본 포스팅에서는 super()가 단순히 "부모 클래스"를 호출하는 함수가 아니라는 점을 명확히 하고, 다중 상속 구조에서 파이썬이 메서드를 찾는 핵심 메커니즘인 MRO(Method Resolution Order)C3 선형화(C3 Linearization) 알고리즘을 분석하여 다이아몬드 상속 문제를 해결하는 전문적인 통찰을 제공합니다.


1. super()에 대한 흔한 오해와 진실

많은 입문자가 super()를 "부모 클래스의 메서드를 호출하는 도구"라고 정의합니다. 하지만 이는 단일 상속에서만 유효한 설명입니다. 다중 상속 구조에서 super()MRO 리스트 상의 다음(Next) 클래스를 찾아가는 동적인 포인터 역할을 수행합니다.

즉, super()는 계층 구조상 위가 아니라, 결정된 리스트의 '옆'에 있는 클래스를 찾아갈 수도 있다는 사실이 다중 상속 해결의 핵심입니다.


2. MRO(Method Resolution Order) 결정 방식의 차이

파이썬은 메서드 탐색 순서를 결정하기 위해 과거에는 깊이 우선 탐색(DFS)을 사용했으나, 현대 파이썬(Python 3)은 C3 선형화 알고리즘을 사용합니다. 이 알고리즘은 다음 두 가지 주요 원칙을 준수합니다.

  1. 로컬 우선순위 유지: 자식 클래스는 항상 부모 클래스보다 먼저 탐색됩니다.
  2. 단조성(Monotonicity): 상속 계층의 순서가 선형화된 결과에서도 모순 없이 유지되어야 합니다.
구분 항목 단일 상속 구조 다중 상속 구조 (C3)
탐색 경로 직계 부모로의 수직적 이동 MRO 리스트에 따른 동적 결정
동작 예측 직관적이고 단순함 비직관적일 수 있으나 정교함
다이아몬드 문제 해당 사항 없음 C3 선형화로 중복 호출 방지

3. Sample Example: 다이아몬드 상속 구조의 메서드 호출 해결

아래 코드는 super()가 어떻게 여러 클래스를 순차적으로 방문하여 중복 실행 없이 모든 메서드를 실행하는지 보여주는 전형적인 예시입니다.


class Base:
    def action(self):
        print("Base Action")

class A(Base):
    def action(self):
        print("Enter A")
        super().action()
        print("Exit A")

class B(Base):
    def action(self):
        print("Enter B")
        super().action()
        print("Exit B")

class Child(A, B):
    def action(self):
        print("Enter Child")
        super().action()
        print("Exit Child")

# 실행 결과 분석
c = Child()
c.action()

# MRO 확인 방법
print(Child.__mro__)

코드 분석과 메커니즘 설명

Child 클래스의 MRO는 Child -> A -> B -> Base -> object 순서로 생성됩니다. Child 내부의 super().action()이 호출되면 A.action을 찾아가고, A 내부의 super().action()Base가 아닌 MRO 상의 다음 클래스인 B를 호출합니다. 이것이 바로 다중 상속에서 super()가 해결하는 핵심적인 마법입니다.


4. 전문적 설계 지침: super() 사용 시 주의사항

안전하고 유지보수가 용이한 다중 상속 구조를 설계하기 위해서는 다음 3가지 규칙을 반드시 지켜야 합니다.

  • 협력적 상속(Cooperative Inheritance): 상속 계층의 모든 클래스는 동일한 시그니처를 가진 메서드에서 반드시 super()를 호출해야 합니다. 호출이 끊기면 MRO 상의 다음 클래스들이 실행되지 않습니다.
  • 메서드 인자 일치: 다중 상속 관계에 있는 메서드들은 가급적 동일한 인자 구성을 가져야 합니다. 차이가 있다면 **kwargs를 활용해 유연하게 대처해야 합니다.
  • 상속 계층의 단순화: 가급적 믹스인(Mixin) 패턴을 활용하여 계층의 깊이를 조절함으로써 MRO 해석의 복잡도를 낮추는 해결 방법이 권장됩니다.

5. 결론: super()는 효율적인 흐름 제어 도구

결론적으로 파이썬의 super()와 MRO는 다중 상속이라는 복잡한 퍼즐을 풀기 위한 정교한 설계도입니다. 단순히 "위"를 보는 것이 아니라 "정해진 순서의 다음"을 본다는 철학을 이해할 때, 우리는 비로소 파이썬다운(Pythonic) 강력한 객체 지향 설계를 완성할 수 있습니다. Child.mro() 메서드를 수시로 확인하며 코드의 흐름을 예측하는 습관이 전문 개발자로 가는 지름길입니다.


내용 출처 및 기술 참조

  • Python Software Foundation. "The Python 2.3 Method Resolution Order." (Official Technical Reference)
  • Raymond Hettinger. "Python's super() Considered Super!" (Advanced Python Technique)
  • Guido van Rossum. "Method Resolution Order in Python." (The Python History Blog)
728x90