프로그래밍백엔드 개발자

파이썬에서 클래스 상속 시 속성 탐색 순서 메커니즘(MRO - Method Resolution Order)은 어떻게 작동합니까? 메서드 해석 순서를 이해하는 것이 왜 중요한지, 그리고 이를 어떻게 알거나 변경할 수 있습니까?

Hintsage AI 어시스턴트로 면접 통과

답변

메서드 해석 순서(MRO, Method Resolution Order)는 파이썬에서 다중 상속의 경우 메서드 및 속성을 검색할 때 어떤 순서로 클래스를 탐색할지를 정의하는 메커니즘입니다.

C3 선형화(C3 linearization)는 메서드 해석 순서를 구성하기 위해 사용되는 알고리즘입니다. MRO를 이해하는 것은 복잡한 클래스 계층 구조를 설계할 때 중요하여 모호함과 예기치 않은 메서드 동작을 피할 수 있습니다.

모든 클래스의 MRO를 확인할 수 있는 방법은 __mro__ 속성이나 mro() 함수를 사용하는 것입니다:

class A: def hello(self): print('A') class B(A): def hello(self): print('B') class C(A): def hello(self): print('C') class D(B, C): pass print(D.__mro__) # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) obj = D() obj.hello() # 'B', 왜냐하면 B가 MRO에서 C보다 앞에 있기 때문입니다.

MRO는 명시적으로 변경할 수는 없지만 기본 클래스의 나열 순서를 제어할 수 있습니다.

함정 질문

클래스가 여러 부모로부터 상속받을 때 메서드는 어떤 순서로 호출될까요? 예를 들어:

class Base: def foo(self): print('Base') class Left(Base): def foo(self): print('Left') super().foo() class Right(Base): def foo(self): print('Right') super().foo() class Child(Left, Right): pass Child().foo()

많은 사람들이 "foo"가 Left에서 호출되고, 다음에 Right, 그 다음에 Base에서 호출될 것이라고 생각합니다 — 실제로 그렇게 됩니다. 하지만 기본 클래스의 순서를 바꾸면 (class Child(Right, Left)) 순서가 바뀝니다!

정답:

호출 순서는 MRO에서 정의된 대로 이루어집니다. 첫 번째 경우 — Left, Right, Base입니다. MRO는 특정 알고리즘(C3 선형화)에 따라 구성됩니다:

[Child, Left, Right, Base, object]

실제 오류 사례


이야기

다중 상속 로직, 메서드 재정의

개발 팀은 믹스인을 위해 다중 상속을 사용했습니다. 하지만 기본 클래스의 잘못된 순서로 인해 믹스인의 공통 로직이 자식 클래스에 의해 "재정의"되어 비즈니스 로직의 일부가 실행되지 않아 데이터 손실이 발생했습니다.


이야기

부모의 잘못된 메서드가 호출됨

파괴자 메서드(__del__)에서 기본 클래스의 메서드가 호출될 것이라고 예상했으나, MRO를 잘못 이해했기 때문에 다른 믹스인에서 상속된 메서드가 호출되어 자원 해제가 이루어지지 않아 메모리 누수가 발생했습니다.


이야기

호출 체인 이해 없이 super() 사용

Python 3 프로젝트에서 클라이언트가 다중 상속을 사용하여 코드 일부를 다시 작성하면서 super() 호출을 업데이트하는 것을 잊었습니다. 이로 인해 메서드가 잘못된 메서드 해석 순리로 인해 자신을 계속 호출하게 되는 무한 재귀 상황이 발생했습니다.