Метаклассы и сопоставление шаблону

Это две совсем разные темы, если что). Или три, если успеем «Введение в аннотации». TODO А успеем ли?

Не-метаклассы

Частые приёмы программирования:

Метаклассы

Предуведомление: Тим Петерс про метаклассы ☺.

Посылка: в питоне всё — объект. Объекты-экземпляры класса конструируются с помощью вызова самого класса. А кто конструирует класс? Мета-класс!

Хороший пример real-life кода на Python, эксплуатирующий метаклассы и многое другое:

Итак, что уже и так может служить конструктором класса?

Зачем тогда нужны ещё отдельные конструкторы классов?

  1. Чёткого ответа нет.
  2. Чтобы закрыть дурную бесконечность (кто конструирует конструктор?) — но это ответ на вопрос «почему?», а не «зачем?»
  3. Чтобы разделить иерархию классов, которой пользуется программист, и то, как конструируется сам базовый класс этой иерархии
    • «Тонкая настройка» класса к моменту его создания уже произошла, и в самом классе этих инструментов нет

    • ⇒ более чистый mro(), чем в случае наследования

    • ⇒ Два похоже работающих класса с общим метаклассом не имеют общего предка
  4. Чтобы сами метаклассы тоже можно было организовывать в виде дерева наследования

Использование type()

Подробности:

Общая картина:

Два примера:

Сопоставление шаблону

Базовая статья: pep-636 (а также pep-635 и pep-634)

Главная сложность: конструкция match … case имеет отличный от Python синтаксис! Спасибо смене парсера с LL(1) на PEG.

Пересказ tutorial:

Введение в аннотации

Базовая статья: О дисциплине использования аннотаций

Duck typing:

Однако:

Поэтому нужны указания о типе полей классов, параметрах и возвращаемых значений функций/методов и т. п. — Аннотации (annotations)

Пример аннотаций полей (переменных), параметров и возвращаемых значений

Составные и нечёткие типы

составные типы:

Более полная лекция по использованию аннотаций для статической типизации в Python планируется в допглавах магистерского курса.

Д/З

  1. Прочитать про:
  2. EJudge: MetaBool 'Класс с пустотой'

    Написать метакласс empty так, чтобы объекты, порождаемые созданным с его помощью классом, считались пустыми, если хотя бы одно из полей, которое присутствует в __dict__ объекта, пусто. Поля класса проверять не надо.

    Input:

       1 class C(metaclass=empty):
       2     cfield = 0
       3     def __init__(self, val=0):
       4         self.ofield = val
       5 print(not C(), not C(""), not C(123))
    
    Output:

    True True False
  3. EJudge: MatchTurtle 'Интерпретатор с черепашкой'

    С помощью конструкции match / case (и только её, условные операторы и иные конструкции с if в этой задачи не разрешены) написать программу, которая в цикле вводит и интерпретирует перечисленные ниже команды перемещения «черепашки» по координатной плоскости. Конец ввода — пустая строка. Изначально черепашка находится в точке 0, 0. Все «слова» в команде разделены ровно одним пробелом.

    • move направление, где направление — это s, n, w или е: переместить черепашку на один шаг вниз, вверх, влево или вправо соответственно.

    • move: переместить черепашку в том же направлении, указанном последней командой вида move направление. Если такой команды ещё не было, черепашка не перемещается.

    • Все остальные команды вида move что-то там должны выводить текст Cannot move to что-то там, и не перемещать черепашку

    • retreat: переместить черепашку в направлении, обратном последней команде вида move направление. Если такой команды ещё не было, черепашка не перемещается.

    • info что, где что — это x , y или xy: вывести абсциссу, ординату или пару «абсцисса ордината»

    • say какое-то сообщение вывести «какое-то сообщение» (включая пустое)

    • все остальные команды игнорируются

    Перед выходом из программы дополнительно выполняется команда info xy.

    Input:

    say Hello, world!
    move n
    move e
    jump
    info xy
    move n
    move base
    look around
    info x
    retreat
    retreat
    info y
    Output:

    Hello, world!
    1 1
    Cannot move to base
    1
    0
    1 0
  4. EJudge: MetaPosition 'Метакласс с заготовками'

    Написать метакласс positioned, который добавляет в создаваемый с его помощью класс три свойства:

    • Строковое представление экземпляра этого класса должно выглядеть как "поле1=значение1 поле2=значение2 …" для всех аннотированных полей этого класса (в порядке их появления в аннотации).

    • При создании экземпляра класса ему можно передавать произвольное количество параметров (включая ноль). Первый параметр инициализирует первое аннотированное поле в этом экземпляре, второй — второе и т. д.; если параметров больше, чем аннотированных полей, они отбрасываются
    • При сопоставлении шаблону допускается позиционное сопоставление с аннотированными полями (в порядке появления в аннотации)
    Input:

       1 class C(metaclass=positioned):
       2     a: int = 1
       3     b: float = 42.0
       4 
       5 for c in C(), C(4), C(100.0, 500), C(7, 2):
       6     print(c)
       7     match c:
       8         case C(1):
       9             print("C1", c.b)
      10         case C(b=42):
      11             print("C42", c.a)
      12         case C(100, 500):
      13             print("C100500")
      14         case C():
      15             print("C", c)
    
    Output:

    a=1 b=42.0
    C1 42.0
    a=4 b=42.0
    C42 4
    a=100.0 b=500
    C100500
    a=7 b=2
    C a=7 b=2

LecturesCMC/PythonIntro2023/12_MetaclassMatch (последним исправлял пользователь FrBrGeorge 2023-11-30 11:46:52)