노트

파이썬 MRO와 super()

Python Method Resolution Order (MRO) and super()

CS#python · 연결된 개념 5개

쉽게 말하면

MRO는 다중 상속에서 메서드를 찾을 때 클래스들을 한 줄로 세운 계주 순서예요. 각 클래스가 super()로 바통을 다음 주자에게 넘기니, 공통 조상까지 모두 한 번씩만 달려요.

비유가 깨지는 곳 super()의 다음 주자는 '내 부모'가 아니라 지금 인스턴스의 MRO에서 내 다음 클래스예요. 그래서 다이아몬드 상속에서 B 안의 super()가 A가 아니라 C를 부를 수 있어요.

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 A

C3 선형화의 규칙

  • 자식이 부모보다 먼저 온다
  • 클래스 정의에 적은 부모 순서를 지킨다(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

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 템플릿 메서드 패턴

    알고리즘의 뼈대(단계의 순서)는 상위 클래스의 메서드에 고정하고, 일부 단계만 하위 클래스가 바꾸게 하는 패턴.

  • 추상 기반 클래스 (ABC)

    추상 기반 클래스(Abstract Base Class, ABC)는 자식 클래스가 반드시 구현해야 할 메서드를 선언해 두는 클래스다. 추상 메서드를 하나라도 구현하지 않은 클래스는 인스턴스를 만들 때 TypeError가 난다.

  • 파이썬 모듈과 패키지

    파이썬에서 .py 파일 하나가 모듈(module)이고, 모듈을 모은 디렉터리가 패키지(package)다. import는 다른 모듈의 변수·함수·클래스에 접근할 수 있게 해 주고, 모듈은 처음 import될 때 한 번만 실행된 뒤 캐시된다(sys.modules).

  • 스프링 AOP

    AOP(Aspect-Oriented Programming, 관점 지향 프로그래밍)는 로깅·트랜잭션·보안·실행 시간 측정처럼 여러 클래스에 흩어져 반복되는 횡단 관심사(cross-cutting concern)를 한 곳에 모아, 비즈니스 코드를 건드리지 않고 메서드 호출 앞뒤에 끼워 넣는 방법이다. 스프링 AOP는 이를 프록시로 구현한다.

  • 파이썬의 선 (PEP 20)

    팀 피터스가 정리한 파이썬 설계 철학 19줄. 명시성, 단순함, 가독성을 앞세운다.

보기 옵션