2705
Комментарий:
|
5597
|
Удаления помечены так. | Добавления помечены так. |
Строка 34: | Строка 34: |
* {{attachment:1.1.png}} / {{attachment:2.3.png}} * любой обход дерева доберётся до более глубокого метода * Что нужно: |
* {{attachment:1.1.png}} Обход в глубину добирается до `A.v` раньше, чем до `C.v` * {{attachment:2.3.png}} Обход в ширину добирается до `A.v` раньше, чем до `B.v` * Что нужно? ''Линеаризация'': |
Строка 38: | Строка 40: |
* Соблюдение порядка объявления * ⇒ Некоторые ситуации невозможны (слишком симметричные) * '''TODO''' * MRO C3 |
* Соблюдение порядка объявления: `class C(D,E,F): …` ⇒ `[C, D, E, F, …] * ⇒ Некоторые ситуации невозможны * MRO C3 ( |
Строка 45: | Строка 46: |
* [[https://www.python.org/download/releases/2.3/mro/|Описание с примерами]] * Общий принцип * Линеаризация графа наследования классов — это объединение списка линеаризаций всех непосредственных родительских классов * Объединение — это упорядочивание списка линеаризаций по следующему принципу: 1. Рассматриваем список слева направо 1. Если очередной класс не является ничьим ''предком'' из списка, он добавляется в линеаризацию, а из списка удаляется * переход к п. 1. 1. Если очередной класс является чьим-то предком (входит в какую-то линеаризацию не в начало), переходим к следующему классу 1. Если хороших кандидатов не нашлось, линеаризация невозможна * Пример (слегка упрощённый): {{{#!python O = object class F(O): pass class E(O): pass class D(O): pass class C(D,F): pass class B(D,E): pass class A(B,C): pass }}} * Простое наследование (L[X] — линеаризация класса X): {{{ L[O] = O L[D] = D O L[E] = E O L[F] = F O }}} * Множественное наследование {{{ L[B] = B + merge(DO, EO) D? Good L[B] = B + D + merge(O, EO) O? Not good (EO) E? Good L[B] = B + D + E + merge(O, O) O? Good L[B] = BDEO }}} соответственно, {{{ L[C] = CDFO }}} наконец, {{{ L[A]: A + merge(BDEO,CDFO) B? + A + B + merge(DEO,CDFO) D? × C? + A + B + C + merge(DEO,DFO) D? + A + B + C + D + merge(EO,FO) E? + A + B + C + D + E + merge(O,FO) F? + A + B + C + D + E + F + merge(O,O) O? + ABCDEFO }}} То есть: {{{#!pycon >>> A.mro() [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>] }}} * Но если (`B(E,D)` вместо `B(D,E)`): {{{#!python O = object class F(O): pass class E(O): pass class D(O): pass class C(D,F): pass class B(E,D): pass class A(B,C): pass }}} то {{{#!pycon >>> B.mro() [<class '__main__.B'>, <class '__main__.E'>, <class '__main__.D'>, <class 'object'>] >>> A.mro() [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>] }}} |
Наследование
Долги за прошлый раз:
hasattr() и getattr()
__iter__()
__del__()
Наследование
Объектное планирование и ООП
ООП:
Характеристика |
Python3 |
Инкапсуляция (не сокрытие) |
Иерархия пространств имён |
Наследование |
Наследование + C3 MRO |
Полиморфизм |
«Из коробки», т. к. duck typing |
Проксирование?
Хранить родительский объект в виде поля, а все методы нового класса делать обёрткой вокруг методов родительского объекта.
TODO пример
Простое наследование
- Видимость и перегрузка методов
- Преобразование типов и создание новых объектов текущего типа:
type(self)(…)
- Вызов метода родительского класса
super() — прокси-объект, аккумулирующий методы всех родительских классов (см. множественное наследование)
Защита полей от случайной перегрузки («__»)
Множественное наследование
- Проблема ромбовидного наследования:
Обход в глубину добирается до A.v раньше, чем до C.v
Обход в ширину добирается до A.v раньше, чем до B.v
Что нужно? Линеаризация:
- Монотонность C: [C, …, B, …, A] ⇒ D(...(C)...): [D, …, C, …, B, …, A]
Соблюдение порядка объявления: class C(D,E,F): … ⇒ `[C, D, E, F, …]
- ⇒ Некоторые ситуации невозможны
- MRO C3 (
- Общий принцип
- Линеаризация графа наследования классов — это объединение списка линеаризаций всех непосредственных родительских классов
- Объединение — это упорядочивание списка линеаризаций по следующему принципу:
- Рассматриваем список слева направо
Если очередной класс не является ничьим предком из списка, он добавляется в линеаризацию, а из списка удаляется
- переход к п. 1.
- Если очередной класс является чьим-то предком (входит в какую-то линеаризацию не в начало), переходим к следующему классу
- Если хороших кандидатов не нашлось, линеаризация невозможна
- Пример (слегка упрощённый):
- Простое наследование (L[X] — линеаризация класса X):
L[O] = O L[D] = D O L[E] = E O L[F] = F O
- Множественное наследование
L[B] = B + merge(DO, EO) D? Good L[B] = B + D + merge(O, EO) O? Not good (EO) E? Good L[B] = B + D + E + merge(O, O) O? Good L[B] = BDEO
соответственно,L[C] = CDFO
наконец,L[A]: A + merge(BDEO,CDFO) B? + A + B + merge(DEO,CDFO) D? × C? + A + B + C + merge(DEO,DFO) D? + A + B + C + D + merge(EO,FO) E? + A + B + C + D + E + merge(O,FO) F? + A + B + C + D + E + F + merge(O,O) O? + ABCDEFO
То есть:>>> A.mro() [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>]
Но если (B(E,D) вместо B(D,E)):
то>>> B.mro() [<class '__main__.B'>, <class '__main__.E'>, <class '__main__.D'>, <class 'object'>] >>> A.mro() [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>]
- Простое наследование (L[X] — линеаризация класса X):
super(): как всегда — объект-прокси всех методов родительских классов, в в случае множественного наследования аналогов не имеет (это как бы объект несуществующего класса)
Д/З
TODO