MRO(Method Resolution Order, 메서드 탐색 순서)는 다중 상속에서 속성이나 메서드를 찾을 때 파이썬이 어떤 클래스부터 차례로 뒤질지 정한 순서다. 파이썬 3는 C3 선형화(C3 linearization) 알고리즘으로 이 순서를 계산한다.
class A:
def hello(self): print("A")
class B(A):
def hello(self): print("B"); super().hello()
class C(A):
def hello(self): print("C"); super().hello()
class D(B, C):
def hello(self): print("D"); super().hello()
D.__mro__ # (D, B, C, A, object)
D().hello() # D B C AC3 선형화의 규칙
- 자식이 부모보다 먼저 온다
- 클래스 정의에 적은 부모 순서를 지킨다(
D(B, C)면 B가 C보다 먼저) - 모든 클래스에서 이 규칙들이 일관되게(단조롭게) 지켜진다. 지킬 수 없는 상속 구조는 클래스를 정의하는 순간
TypeError가 난다
다이아몬드 상속(diamond inheritance: B와 C가 모두 A를 상속하고 D가 둘을 상속)에서도 A는 한 번만, 맨 뒤에 나온다. 그래서 "다중 상속이면 맨 앞 부모의 메서드를 물려받는다"는 설명은 반만 맞다. 맨 앞 부모에 없으면 그 부모의 부모가 아니라 MRO상 다음 클래스(C)로 넘어간다.
super()는 "부모"가 아니다
super()는 현재 인스턴스의 MRO에서 지금 클래스 다음에 오는 클래스를 가리킨다. 위 예에서 B 안의 super()는 A가 아니라 C를 부른다. 그래서 협력하는 클래스들이 모두 super()를 부르면 MRO를 따라 한 번씩만 호출되는 체인이 만들어진다.
- 협력적 다중 상속(cooperative multiple inheritance)을 하려면 모든 클래스가
super()를 일관되게 부르고,**kwargs를 넘겨 서로 다른 인자를 받아 넘긴다(*args·**kwargs와 언패킹) - 순서는
클래스.__mro__나클래스.mro()로 확인한다
실무에서는
장고·DRF의 믹스인(LoginRequiredMixin, CreateModelMixin)이 MRO에 기대는 대표적인 예다. 믹스인을 기반 뷰보다 왼쪽에 두는 이유가 이것이다(DRF 뷰 계층). 다만 깊은 다중 상속은 추적이 어려우니 상속보다 위임을 먼저 고민한다. 자바스크립트에서 비슷한 고민은 믹스인을 본다. 클래스 기본은 파이썬 클래스 기초에 있다.
출처: The Python 2.3 Method Resolution Order Michele Simionato · Python 튜토리얼: Multiple Inheritance