Различия между версиями 9 и 10
Версия 9 от 2018-11-24 23:27:30
Размер: 2705
Редактор: FrBrGeorge
Комментарий:
Версия 10 от 2018-11-25 11:47:43
Размер: 5597
Редактор: FrBrGeorge
Комментарий:
Удаления помечены так. Добавления помечены так.
Строка 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() — прокси-объект, аккумулирующий методы всех родительских классов (см. множественное наследование)

  • Защита полей от случайной перегрузки («__»)

Множественное наследование

  • Проблема ромбовидного наследования:
    • 1.1.png

      • Обход в глубину добирается до A.v раньше, чем до C.v

    • 2.3.png

      • Обход в ширину добирается до 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 (
    • https://makina-corpus.com/blog/metier/2014/python-tutorial-understanding-python-mro-class-search-path

    • https://habr.com/post/62203/

    • https://ru.wikipedia.org/wiki/C3-линеаризация

    • Описание с примерами

    • Общий принцип
      • Линеаризация графа наследования классов — это объединение списка линеаризаций всех непосредственных родительских классов
      • Объединение — это упорядочивание списка линеаризаций по следующему принципу:
        1. Рассматриваем список слева направо
        2. Если очередной класс не является ничьим предком из списка, он добавляется в линеаризацию, а из списка удаляется

          • переход к п. 1.
        3. Если очередной класс является чьим-то предком (входит в какую-то линеаризацию не в начало), переходим к следующему классу
        4. Если хороших кандидатов не нашлось, линеаризация невозможна
    • Пример (слегка упрощённый):
         1 O = object
         2 class F(O): pass
         3 class E(O): pass
         4 class D(O): pass
         5 class C(D,F): pass
         6 class B(D,E): pass
         7 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
        То есть:
        >>> 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)):

           1 O = object
           2 class F(O): pass
           3 class E(O): pass
           4 class D(O): pass
           5 class C(D,F): pass
           6 class B(E,D): pass
           7 class A(B,C): pass
        
        то
        >>> 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'>]
  • super(): как всегда — объект-прокси всех методов родительских классов, в в случае множественного наследования аналогов не имеет (это как бы объект несуществующего класса)

Д/З

TODO

LecturesCMC/PythonIntro2018/10_Inheritance (последним исправлял пользователь FrBrGeorge 2018-11-28 01:21:53)