Аннотации и статическая типизация

Аннотации

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

(немного копипасты из ../12_MetaclassMatch

Duck typing:

Однако:

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

<!> Аннотации настолько отвязаны от реализации, что, например, получить доступ к собственным аннотациям из функции, например, довольно трудно, и получается «хрупкий» код (с классами гораздо проще)

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

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

Статическая модель типизации

Модуль typing

⇒ Это тема для целого курса.

Кратко:

Пример: dataclasses — типизированные структуры, логика базируется на аннотациях

MyPy

Что показательно:

  1. Статическая типизация в Python очень активно развивается, достаточно посмотреть сводный What's New и поискать там «type» или «typing».

  2. три официальных блога Гвидо: The Mypy Blog, Neopythonic, The History of Python

Совпадение? Не думаю!™

Ещё раз: зачем аннотации?

http://www.mypy-lang.org: статическая типизация в Python by default (ну, почти… или совсем!)

На MyPy основано большинство дисциплин разработки и систем проверки кода в различных IDE.

Компиляция

Пример для mypyc:

Д/З

  1. Прочитать про
  2. EJudge: CookedStruct 'Класс с преобразованием'

    (фактически это упражнение). Написать класс Cooked, который будет использовать аннотации к полям этого класса в качестве функций преобразования значений во время присваивания их полям (см. пример). Исключения, которые могут возникнуть во время присваивания, не обрабатывать. Предусмотреть также преобразование в строку, которое должно возвращать перечень аннотированных полей (в порядке их появления в словаре аннотаций и если они присутствуют в объекте) в формате ":имя=значение …:"; если таких полей нет, выводится "::".

    Input:

       1 class C(Cooked):
       2     a: int
       3     b: lambda x: x % 2
       4     d = 100500 
       5 
       6 c = C()
       7 c.a, c.b = "1234", 5
       8 print(c)
    
    Output:

    :a=1234 b=1:
  3. EJudge: DodgsonDet 'Определитель'

    Ввести квадратную целочисленную матрицу построчно и посчитать её определитель (например, методом конденсации Доджсона). Размер матрицы (1<N⩽20) определяется длиной её нулевой строки. Описание предлагаемого метода в подсказках. Пользоваться numpy.linalg.det(arr) нельзя ☺.

    • Дополнительно текст программы будет проверяться mypyc --strict, ошибок быть не должно

    Input:

    8, 8, 5, 6, 3
    1, 4, 4, 9, 0
    9, 6, 7, 7, 3
    4, 1, 0, 1, 4
    6, 7, 9, 7, 3
    Output:

    2784
  4. EJudge: StrictSort 'Строгая сортировка'

    (эту задачу надо сдавать в EJudge, но некоторые свойства решения там пока проверить нельзя) Написать:

    • функцию defkey(element: Comparable) -> Comparable, которая вычисляет значение ключа сортировки по следующему принципу:

      • Если element имеет длину, то ключ — это длина

      • Иначе ключ — это сам element (это допустимо в силу его типа)

    • функцию strictsort(seq: Sortable, key: Callable[[Comparable], Comparable] = defkey) -> Sortable:, которая сортирует элементы изменяемой последовательности (в самой последовательности) и возвращает эту последовательность

    Должно быть определено два дополнительных типа:

    • Comparable — тип, в котором есть операция сравнения (для простоты — на меньше)

    • Sortable — изменяемая индексируемая последовательность элементов типа Comparable

    В результате приведённый пример должен проходить mypy --strict, а любая закомментированная строка из примера — вызывать ошибку проверки/компиляции (строго до runtime).

    Input:

       1 c: Sortable = [6, 1, 4, 2, 7, 2, 8, 3]
       2 print(*strictsort(c))
       3 print(*strictsort([6., 1., 4., 2., 7., 2., 8., 3.]))
       4 print(*strictsort(["234", "sdf23452345234gg", "45645674567", "ASDASD"]))
       5 print(*strictsort([(1, 2, 4, 9), (2, 7, 4, 6, 8), (1,), (8, 9, 23), (7, 2, 1)]))
       6 print(defkey(9), defkey("999"))
       7 # c: Sortable = [7j, 2j, 3j]
       8 # defkey(iter("123"))
       9 # print(*strictsort({1: 2, 3: 4}))
    
    Output:

    1 2 2 3 4 6 7 8
    1.0 2.0 2.0 3.0 4.0 6.0 7.0 8.0
    234 ASDASD 45645674567 sdf23452345234gg
    (1,) (8, 9, 23) (7, 2, 1) (1, 2, 4, 9) (2, 7, 4, 6, 8)
    9 3

LecturesCMC/PythonIntro2024/33_StaticTyping (последним исправлял пользователь FrBrGeorge 2024-12-15 19:22:34)