Страницы

Поиск по вопросам

пятница, 20 декабря 2019 г.

Почему порядок разрешения методов в python в примере работает именно так

#python #python_3x


Код:

class A:
     pass


class B(A):
    pass


class C(A):
    pass


class D(B):
    pass


class E(B, C):
    pass


class K(C):
    pass


class G(D, E):
    pass


class J(E, K):
    pass


class M(G, J):
    pass


print(M.mro())


stdout:

[, , , ,
, , , ,
, ]


Сперва думал, что в приоритете для 'mro' это 'замыкание' возникающих ромбов, но на
данном примере убедился, что это не так.
    


Ответы

Ответ 1



В Python используется алгоритм порядка разрешения методов C3. Алгоритм C3 представляет из себя набор следующих правил: Линеаризация класса C есть одноэлементный список из самого класса C плюс объединение линеаризаций его родителей и списка всех его родителей. В условных обозначениях это можно записать как L[C] = [C] + merge(L[C1], L[C2], …, L[CN], [C1, C2, …, CN]), если класс C был объявлен как class C(C1, C2, …, CN). Надо отметить, что каждая линеаризация L[CX] начинается с класса CX, который был дополнительно приписан в конец списка объединения как непосредственный родитель класса C. Зачем это сделано станет ясно далее. Объединение линеаризаций происходит следующим образом: Берётся нулевой элемент из первой линеаризации (L[C1][0]). Этот элемент ищется во всех других линеаризациях (от L[C2] до L[CN]). Если этот элемент найден где-то вне начала списка (L[CK][X] == L[C1][0], X != 0; по сути это значит, что L[C1][0] является чьйм-то предком), то алгоритм переходит к первому шагу, беря в качестве нулевого элемент из следующей линеаризации (L[C2][0]). Если элемент нигде не найден в позиции отличной от нулевой, то он добавляется в конец итогового списка линеаризации и удаляется из всех рассматриваемых списков (от L[C1] до L[CN]; один и тот же класс не может встречаться в итоговом списке дважды). Если после удаления элемента остались пустые списки — они исключаются из объединения. После этого алгоритм повторяется с самого начала (от нового элемента L[C1][0]), если он есть. Если его нет — объединение закончено. Если алгоритм дошёл до последнего элемента L[CN], но ни один из нулевых элементов не удовлетворяет правилам, то линеаризация не возможна. Источник: https://habr.com/ru/post/62203/ Я вручную построил граф наследования и рассчитал линеаризацию для Вас: """ object | A / \ B C / \ / \ D E K \ / \ / G J \ / M L[M] = [M] + merge(L[G], L[J], [G, J]) = [M] + merge([G, D, E, B, C, A, object], [J, E, B, K, C, A, object], [G, J]) = [M] + [G] + merge([D, E, B, C, A, object], [J, E, B, K, C, A, object], [J]) = [M] + [G] + [D] + merge([E, B, C, A, object], [J, E, B, K, C, A, object], [J]) = [M] + [G] + [D] + [J] + merge([E, B, C, A, object], [E, B, K, C, A, object]) = [M] + [G] + [D] + [J] + [E] + merge([B, C, A, object], [B, K, C, A, object]) = [M] + [G] + [D] + [J] + [E] + [B] + merge([C, A, object], [K, C, A, object]) = [M] + [G] + [D] + [J] + [E] + [B] + [K] + merge([C, A, object], [C, A, object]) = [M] + [G] + [D] + [J] + [E] + [B] + [K] + [C, A, object] = [M, G, D, J, E, B, K, C, A, object] L[G] = [G] + merge(L[D], L[E], [D, E]) = [G] + merge([D, B, A, object], [E, B, C, A, object], [D, E]) = [G] + [D] + merge([B, A, object], [E, B, C, A, object], [E]) = [G] + [D] + [E] + merge([B, A, object] + [B, C, A, object]) = [G] + [D] + [E] + [B] + merge([A, object], [C, A, object]) = [G] + [D] + [E] + [B] + [C] + merge([A, object], [A, object]) = [G] + [D] + [E] + [B] + [C] + [A, object] = [G, D, E, B, C, A, object] L[J] = [J] + merge(L[E], L[K], [E, K]) = [J] + merge([E, B, C, A, object], [K, C, A, object], [E, K]) = [J] + [E] + merge([B, C, A, object], [K, C, A, object], [K]) = [J] + [E] + [B] + merge([C, A, object], [K, C, A, object], [K]) = [J] + [E] + [B] + [K] + merge([C, A, object], [C, A, object]) = [J] + [E] + [B] + [K] + [C, A, object] = [J, E, B, K, C, A, object] L[D] = [D] + merge(L[B], [B]) = [D] + merge([B, A, object], [B]) = [D] + [B] + merge([A, object]) = [D] + [B] + [A, object] = [D, B, A, object] L[E] = [E] + merge(L[B], L[C], [B, C]) = [E] + merge([B, A, object], [C, A, object], [B, C]) = [E] + [B] + merge([A, object], [C, A, object], [C]) = [E] + [B] + [C] + merge([A, object], [A, object]) = [E] + [B] + [C] + [A, object] = [E, B, C, A, object] L[K] = [K] + merge(L[C], [C]) = [K] + merge([C, A, object], [C]) = [K] + [C] + merge([A, object] = [K] + [C] + [A, object] = [K, C, A, object] L[B] = [B] + merge(L[A], [A]) = [B] + merge([A, object], [A]) = [B] + [A] + merge([object]) = [B] + [A] + [object] = [B, A, object] L[C] = [C] + merge(L[A], [A]) = [C] + merge([A, object], [A]) = [C] + [A] + merge([object]) = [C] + [A] + [object] = [C, A, object] L[A] = [A] + merge(L[object], [object]) = [A] + merge([object], [object]) = [A] + [object] = [A, object] L[object] = [object] В итоге: [M, G, D, J, E, B, K, C, A, object] Ваш stdout: [, , , , , , , , , ] """

Комментариев нет:

Отправить комментарий