11.1 Method Resolution Order
메서드 해결 순서 (Method Resolution Order, MRO)는 Python이 클래스 계층 구조에서 메서드와 속성을 찾는 순서를 결정해. 이건 특히 다중 상속을 사용할 때 중요하거든, 클래스가 여러 부모 클래스에서 속성과 메서드를 상속 받을 수 있잖아.
쉽게 말해서, Python이 클래스 상속 트리를 어떻게 탐색하는지에 대한 엄격한 고정된 순서(혹은 알고리즘)가 있어. 이 알고리즘은 메서드를 찾는 올바른 순서를 보장해, 이걸 다음과 같이 설명할 수 있어:
C3 선형화 알고리즘
C3 선형화 알고리즘은 다음을 결합하여 MRO를 결정해:
- 자신의 클래스.
- 부모 클래스 리스트를 나열된 순서대로.
- 부모 클래스의 MRO를 같은 순서로.
C3 선형화 알고리즘 규칙
- 메서드의 로컬 순서를 유지하기: 클래스
A
가 클래스B
앞에 나열되면, 클래스A
의 모든 메서드는 클래스B
의 메서드보다 먼저 고려되어야 해. - 부모 클래스 순서 유지하기: 클래스
A
가 클래스B
의 부모라면, 클래스A
의 모든 메서드는 클래스B
의 메서드보다 먼저 고려되어야 해. - 상속 순서 고려하기: 클래스
C
가 두 개 이상의 클래스의 부모라면, 클래스C
의 메서드 순서는 이 모든 클래스의 MRO에서 유지되어야 해.
알고리즘 단계:
1단계. 자신 클래스부터 시작하기:
언제나 메서드를 호출한 자신 클래스부터 시작해.
2단계. 기본 클래스들을 나열된 순서대로 추가하기:
현재 클래스 다음으로 기본 클래스들을 상속된 순서대로 확인해.
3단계. 부모 클래스 탐색하기:
필드와 메서드를 그곳에서 찾아봐.
4단계. 부모 클래스의 MRO 병합하기:
동일한 기본 클래스가 여러 경로로 상속되더라도, 그 클래스는 한 번만 올바른 순서로 확인되고 나머지는 생략 돼.
"알고리즘과 데이터 구조"에 친숙한 이들에게는 깊이 우선 탐색이지, 너비 우선 탐색이 아니라.
11.2 MRO 확인하기
Python에서 클래스의 메서드와 필드 탐색 순서를 __mro__
속성이나 mro()
함수를 사용하여 확인할 수 있어.
예시:
class A:
def method(self):
print("A")
class B(A):
def method(self):
print("B")
class C(A):
def method(self):
print("C")
class D(B, C):
def method(self):
print("D")
# MRO 확인하기
print(D.__mro__)
출력 결과:
(<class '__main__.D'>,
<class '__main__.B'>,
<class '__main__.C'>,
<class '__main__.A'>,
<class 'object'>)
이것은 Python이 메서드와 속성을 찾는 순서를 보여줘:
D
: Python은 먼저 클래스D
에서 메서드를 확인해.-
B
: 그 다음 Python은 첫 번째 부모 클래스인B
에서 메서드를 확인해. -
C
: 메서드가 클래스B
에서 발견되지 않으면, Python은 두 번째 부모 클래스인C
에서 메서드를 확인해. -
A
: 메서드가B
와C
에서 발견되지 않으면, Python은 클래스A
에서 메서드를 확인해. -
object
: 마지막으로 Python은 기본 클래스object
에서 메서드를 확인해.
11.3 MRO와 함께 super()
사용하기
super()
함수는 부모 클래스 메서드를 올바른 순서로 호출하기 위해 MRO를 따르게 해.
super()
사용 예제를 살펴보자:
class A:
def method(self):
print("A")
super().method()
class B(A):
def method(self):
print("B")
super().method()
class C(A):
def method(self):
print("C")
super().method()
class D(B, C):
def method(self):
print("D")
super().method()
d = D()
d.method()
출력 결과:
D
B
C
A
탐색 순서 (MRO)
1. method
메서드의 클래스 D
호출:
- Python은 클래스
D
에서 메서드를 확인하고, 메서드를 찾아. D.method()
가 실행되고"D"
를 출력해.- 그 다음
super().method()
가 호출되며 다음 메서드를 호출하기 위해 MRO를 따라가.
2. method
메서드의 클래스 B
호출:
- MRO에 따라,
D
다음 클래스는B
야. B.method()
가 실행되고"B"
를 출력해.- 그 다음
super().method()
가 호출되며 다음 메서드를 호출하기 위해 MRO를 따라가.
3. method
메서드의 클래스 C
호출:
- MRO에서
B
다음 클래스는C
야. C.method()
가 실행되고"C"
를 출력해.- 그 다음
super().method()
가 호출되며 다음 메서드를 호출하기 위해 MRO를 따라가.
4. method
메서드의 클래스 A
호출:
- MRO에서
C
다음 클래스는A
야. A.method()
가 실행되고"A"
를 출력해.- 그 다음
super().method()
가 호출되지만A
에는 부모의method
메서드가 없기 때문에 (기본 클래스object
제외), 호출은 추가적인 동작 없이 끝나.