#python #method-resolution-order
#питон #метод-разрешение-порядок
Вопрос:
Может кто-нибудь объяснить, почему этот код печатает Y, а не X? Я ожидал, что он напечатает «X», потому что там написано, что он проходит в классе C, а класс X является следующим суперклассом.
class X:
def foo(self):
return "X"
class Y:
def foo(self):
return "Y"
class A(X):
def foo(self):
return self.met()
class B(A):
def foo(self):
return "B"
class C(X):
pass
class D(C, X):
def met(self):
return "D"
class E(A, D):
def foo(self):
return super().foo()
class F(Y,B):
pass
class G(D, B):
pass
class H(E, A, X):
def met(self):
return "H"
class I(G,F):
pass
print(I().foo())
Извините за длинный код, но я не знаю, как сделать его короче, не делая вопрос неясным
Комментарии:
1. Чтобы сделать ваш вопрос короче и понятнее, я хотел бы предложить вам проверить цепочку MRO, например, с помощью отладочных отпечатков, таких как
print(CLS.__mro__)
. Если вы обнаружите что-то конкретное, что не соответствует вашим ожиданиям, сделайте это главным пунктом вопроса.2. конкретный момент, который не соответствует моим ожиданиям, заключается в том, что после класса C в MRO появляется F, но, насколько я понимаю, класс X должен идти после C.
3. Статья Википедии о линеаризации C3 объясняет, как выполняется упорядочение.
Ответ №1:
На Python Multiple Inheritance: The Diamond Rule
:
- Перечислите все базовые классы, следуя классическому правилу поиска, и включите класс несколько раз, если он посещался неоднократно. В приведенном выше примере список посещенных классов равен [D, B, A, C, A] .
- Просканируйте список на наличие дублированных классов. Если таковые обнаружены, удалите все вхождения, кроме одного, оставив последнее в списке. В приведенном выше примере список становится [D, B, C, A] после удаления дубликатов.
m = ['I', 'G', 'D', 'C', 'X', 'object', 'X', 'object', 'B', 'A',
'X', 'object', 'F', 'Y', 'object', 'B', 'A', 'X', 'object']
s = set()
custom_mro = [i for i in reversed(m) if not (i in s or s.add(i))][::-1]
original_mro = list(i.__name__ for i in I.__mro__)
assert custom_mro == original_mro
print(custom_mro) #['I', 'G', 'D', 'C', 'F', 'Y', 'B', 'A', 'X', 'object']
Y печатается, потому Y
что класс указан первым в порядке mro.