Что такое аннотации типов в Python?

Читая эту статью надеюсь, что вы знакомы с аннотациями в Python. Но все же в вкратце напомню. Они нужны для того, чтобы придать некой строгости нашему динамически типизированному языку.

Утиная типизация
Утиная типизация

Как работает в IDE на примере PyCharm

Уже на этапе разработки мы можем видеть, что используем методы не так,  если их автор писал аннотации к коду.

Подсказки в PyCharm
Подсказки в PyCharm

В примере аргумент функции first ожидает числовое значение, а мы передаем строку. Благодаря современным редакторам кода мы можем избежать потенциальных ошибок.

А что под капотом?

В python аннотации типов читаются на этапе импорта и хранятся в атрибуте __annotations__. Посмотрим, что находится в этом атрибуте у нашего метода custom_sum:

Атрибут __annotations__
Атрибут __annotations__

В этом атрибуте хранится dict, ключу return которого соответствует аннотация возвращаемого типа, идущая после ->.

Для получения аннотаций typing предоставляет метод get_type_hints.

Использование метода get_type_hints
Использование метода get_type_hints

Как видно, значениями в словаре являются реальные классы python.

Накладные расходы?

К сожалению, добавление типов в код на python не дает никакого прироста производительности. Лишь вызывает некоторые накладные расходы:

  1. Импорт модулей занимает больше времени и памяти(так как нужно прочитать аннотации и записать их в атрибут __annotations__);

  2. Ссылка на типы, которые еще не определены требует использования строковых обозначений, а не реальных типов. 

С первым пунктом все понятно. Приведу пример, когда второй пункт может доставить нам сложности.

Пример класса, где метод возвращает экземпляр своего класса
Пример класса, где метод возвращает экземпляр своего класса

Можно видеть проблему “опережающей ссылки”.  Наш класс в одном из методов хочет вернуть экземпляр самого себя, но не сможет этого сделать, поскольку объект класса еще не определен, пока Python не закончит вычисление его тела. В этом случае мы вынуждены записать возвращаемое значение в виде строки. Из-за такого поведения аннотации обрабатывались в момент определения функций и модулей, что было вычислительно  затратно(программа должна понять, что эта строка означает).

Одобренный PEP 563 “Postponed Evaluation of Annotations” уменьшил время необходимое для обработки аннотаций типов во время выполнения. Аннотации типов больше не вычисляются в момент определения функции, вместо этого они сохраняются в аннотациях в строковой форме(не производя никаких вычислений). Чтобы достичь этого нужно сделать один import

Работа импорта
Работа импорта

Благодаря импорту from __future__ import annotations можно увидеть, что типы стали простыми строками, хотя не определены, как типы в кавычках. Изначально, планировалось сделать такое поведение поведением по умолчанию(не импортируя ничего). Но разработчики FastAPI и pydantic настояли на том, чтобы эта часть была опциональной так как она ломает работу этих библиотек.

MyPy

MyPy нужен для статической проверки типов в Python. Эта библиотека проверяет наши аннотации и как мы ими пользуемся. Приведу совсем небольшой пример, подробнее можно ознакомится по ссылке:

test_file.py для проверки MyPy
test_file.py для проверки MyPy

При вызове функции test_func мы ошибочно передаем вместо str тип int.  MyPy  помогает нам понять, что мы что-то делаем не так:

Ответ MyPy
Ответ MyPy

Интересные примеры аннотаций

Я не буду рассказывать про базовые типы, по типу str, int и тд. Так же опущу распространенное типы из библиотеки typing по типу List, Union, Optional так как об этом очень много информации.

Аннотирование *args **kwargs

Можно установить какие типы должен принимать *args **kwargs. В коде ниже указано, что args принимает только строковые значения, а kwargs только число. 

Пример type hints для 8agrs **kwargs
Пример type hints для 8agrs **kwargs

MyPy выдаст следующую ошибку:

Ошибка от MyPy
Ошибка от MyPy

Суть ошибки в том, что все неименованные аргументы *args  ждут тип str, мы же передаем int.

Объект является подтипом

Если  даны 2 класса User и ProUser,  который наследует User. В таком случае мы можем передавать методу, ожидающему User тип ProUser.

Пример работы с подтипами
Пример работы с подтипами
Ответ от MyPy
Ответ от MyPy

Вызываемые аргументы

Так же мы можем  аннотировать аргумент функции, даже если он является другой функцией, благодаря Callable  из модуля typing. С помощью этого инструмента можно так же указать, что ждет  функция и что она возвращает. В нашем случае метод bar принимает str и возвращает None.

Вызываемые аргументы
Вызываемые аргументы

Аннотирование переменных

До этого момента мы говорили лишь об аннотациях аргументов функций и возвращаемых значений. Помимо этого, аннотировать можно еще переменные.

Если говорить о себе - я не использую аннотации переменных. Так как типизация функций помогает нам работать с интерфейсами, тогда как работа  с переменными только увеличивает время разработки. Если есть большое желание указывать типы везде - стоит присмотреться к другому языку программирования.

Типизация для декораторов

Зачастую аннотировать декораторы - не самая хорошая идея. Они не только не улучшают чтение кода, а делают более непонятным происходящее. Приведу пример найденного аннотирования декоратора на просторах интернета:

Выглядит так себе, правда?
Выглядит так себе, правда?

Так что в итоге?

К сожалению, в Python типизация не дает никакого прироста производительности, а только потенциальное замедление и увеличение потребления памяти. Так же, чтобы корректно ее использовать - нужно потратить определенное время, чтобы разобраться что к чему. 

Если говорить о философии языка - он не про это, python больше про скорость разработки и простоту использования. Аннотация раскрывает себя во всей красе на больших проектах, когда нам важна общая надежность системы. Такие инструменты как MyPy подскажут нам на то, что мы делаем не так. Говоря о небольших проектах “на скорую руку” или скриптах  - я бы не стал использовать типизацию.

Из интересного можно подметить, что далеко не все core разработчики самого Python используют Type hints в своем коде.

Сам я уже не могу не использовать аннотации, для меня это вошло в привычку, для меня это как правило хорошего тона в разработке. Но своих коллег по работе принуждать к типам я не стану, а скорее просто делюсь преимуществами их использования.

Дорогой ценой я выучил урок: для небольших программ динамическая типизация - благо. Но для более крупных программ необходим более дисциплинированный подход. 

Гвидо Ван Россум, фанат Монти Пайтон

Полезные источники

Ромальо Л. PYTHON. К вершинам мастерства / 2-е издание / Москва: ДМК пресс, 2022. - 897

MyPy documentation - URL: https://mypy.readthedocs.io/en/stable/

PEP 484 – Type Hints - URL: https://peps.python.org/pep-0484/

PEP 483 – The Theory of Type Hints - URL: https://peps.python.org/pep-0483/

typing — Support for type hints - URL: https://docs.python.org/3/library/typing.html

Комментарии (58)


  1. tumbler
    15.03.2024 06:57
    +1

    По опыту, большинство аннотаций помогают тому же PyCharm с автокомплитом - что несомненно плюс.

    Использование MyPy может найти пару ошибок в аннотациях (но и только!) - тут скорее минус, с учетом времени, которое можно потратить на попытки убедить MyPy в том, что ты правильно всё аннотировал.


    1. gromyko21 Автор
      15.03.2024 06:57
      +1

      Да, порой с MyPy приходится потанцевать, но мое мнение - он все же помогает повысить стабильность системы.


  1. ednersky
    15.03.2024 06:57

    Ох.

    Всё это "типовое" поветрие давно (ЕМНИП в 1993м году) уже под лупой исследовано Ларри Уоллом.

    Когда Ларри разбирал призыв: "переходите на типы", то он наткнулся, что кроме вот этого мема никто ничего в аргументы не приводит:

    Комментарий для зануд (конечно, Ларри рассматривал современный ему мем, речь всё-таки о 1993 годе).

    Так вот, увидев, что НИКАКИХ других обоснований к призывам использовать типы у адептов типов нет, Ларри рассмотрел примеры из мема и сделал вывод:

    проблема здесь состоит не в типах, а в неоднозначном применении оператора "плюс". В одном случае он означает "математическое сложение", а в другом - "конкатенация".

    Далее, Ларри предложил в новых языках программирования разделять эти операторы, выделяя их в разные значки, и многие языки стали следовать этому правилу. И в них неоднозначности из мема нет. И необходимости в типах тоже нет.

    И нагрузки на программиста "размечай свой код, чтобы сделать компилятор счастливым" - тоже нет.


    1. gromyko21 Автор
      15.03.2024 06:57
      +1

      Интересная картинка, кажется та же проблема остается по сей день в JS?)


      1. Sap_ru
        15.03.2024 06:57
        +2

        Хуже того. Она учащается и в TS частично перекочевать, так как операторы сравнений работают также, а это проблема не столько типов, сколько приведения типов


      1. ednersky
        15.03.2024 06:57

        джаваскрипт с тех пор не реформировали


    1. fireSparrow
      15.03.2024 06:57
      +6

      Речь-то в статье вообще про другое. В питоне и так типы есть, сложить строку с числом у вас не получится. Проблема в том, что тип становится известен только в процессе выполнения.

      Поддерживать код, у которого не размечены типы - очень-очень больно.

      Сейчас я работаю на проекте, где в одном из сервисов есть огромное число функций, которые принимают аргумент opts, или params, или оба этих аргумента одновременно. Эти аргументы являются словарями, которые формируются постепенно - то есть по мере того, как они пробрасываются из функции в функцию, они могут обогащаться новыми ключами.

      В итоге глядя только на функцию, вы не можете знать, какие ключи вообще есть в этих словарях, и какой формат могут иметь их значения. Приходится каждый раз долго лазить по всему коду, и всё равно полной уверенности нет.

      А если бы в эти аргументы передавались датаклассы, и были бы проставлены соответствующие аннотации, то это полностью избавило бы меня от такой проблемы.


      1. ednersky
        15.03.2024 06:57

        Речь-то в статье вообще про другое. В питоне и так типы есть, сложить строку с числом у вас не получится.

        а сконкатенировать?

        А если бы в эти аргументы передавались датаклассы, и были бы проставлены соответствующие аннотации,

        ужас какой

        разве аннотаций недостаточно?


        1. fireSparrow
          15.03.2024 06:57

          >> разве аннотаций недостаточно?

          Ну, если у вас словарь, то вы, конечно, можете написать аннотацию dict[string, Any], но толку тут не много, вы всё-равно не знаете, какие ключи в этом словаре. А в датаклассе полностью определён перечень полей и типы их значений.


          1. ednersky
            15.03.2024 06:57

            под аннотациями я имел в виду текстовый комментарий разработчика перед заголовком функции. Возможно на специальном языке разметки


            1. fireSparrow
              15.03.2024 06:57

              В питоне под аннотациями понимают вполне конкретную вещь. В статье речь именно про питоновские аннотации.


        1. fireSparrow
          15.03.2024 06:57

          >> а сконкатенировать?

          А что вы вообще подразумеваете под конкатенацией строки и числа применительно к питону? И чем это отличается от сложения строки и числа?


          1. ednersky
            15.03.2024 06:57

            под конкатенацией я подразумеваю конкатенацию

            совершенно очевидно (и иных прочтений быть не может) что означает конкатенация:

            конкатенация(1, 2)

            конкатенация('1', '2')

            конкатенация('ф', 'у')

            конкатенация('ф', 2)

            а под сложением я понимаю сложение

            совершенно очевидно (и иных прочтений быть не может) что означает сложение:

            сложение(1, 2)

            сложение('1', '2')

            сложение(1, '2')

            И я говорю о проблеме в целом (об исследовании Ларри), а не о Python конкретно.

            То, что Python криво задизайнили и теперь пытаются вылечить головную боль методом внедрения гильотин - отдельный разговор.

            Хотя у Python есть опыт обратнонесовместимых шагов (Python2 -> 3), могли бы и нормально поправить дизайн.


            1. rSedoy
              15.03.2024 06:57
              +1

              вы упорно приводите примеры проблемы, которой нет в Python, вам упорно говорят, что тут подняли немного другую проблему


              1. ednersky
                15.03.2024 06:57

                Как же проблемы в Python нет, если она есть, и именно на её решение и направлена вся эта возня с типами?


                1. rSedoy
                  15.03.2024 06:57
                  +3

                  Ваш пример для ЯП со слабой типизацией, у python она строгая, а тут подняли проблему динамической типизации, это как бы совсем другое.


            1. fireSparrow
              15.03.2024 06:57

              >> То, что Python криво задизайнили

              А в чём именно вы видите кривой дизайн? В том, что в питоне нельзя по ошибке применить конкатенацию вместо сложения?

              >> пытаются вылечить головную боль методом внедрения гильотин

              А вот здесь вообще о чем речь? Ещё раз повторюсь - в питоне вообще нет никакой путаницы сложения и конкатенации. Поэтому в питоне никто не пытается решить эту проблему, за отсутствием проблемы. Аннотации используются вообще для другого.

              >> И я говорю о проблеме в целом (об исследовании Ларри), а не о Python конкретно.

              О какой проблеме-то? Во многих языках (включая питон) нет проблемы с неоднозначностью сложения/конкатенации, а польза от типов - есть.

              И типы, внезапно, нужны не только для того, чтобы сделать счастливым компилятор. А ещё и для того, чтобы сделать работу программиста проще и сократить число ошибок.

              И, кстати, почему вы упорно называете Ларри Уолла только по имени? Вы с ним лично знакомы?


              1. ednersky
                15.03.2024 06:57

                А в чём именно вы видите кривой дизайн? В том, что в питоне нельзя по ошибке применить конкатенацию вместо сложения?

                Именно что можно. Ведь оператора конкатенации в Python нет, там есть оператор "плюс", который выполняет и операцию сложения и операцию конкатенации.

                отсюда следует то, что программист начинает быть обязан приводить типы к одному виду, прежде, чем он вызовет нужный ему оператор.

                и именно отсюда следует вся эта возня с типами в бестиповом языке.

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

                если вы пишете функцию, вычисляющую факториал, то не нужно пытаться чтобы попутно она считала и числа Фибоначчи - написать такое можно, но в итоге получится нечто неправильное, кривое, что трудно исправлять.

                ровно так и с операторами конкатенации и сложения


                1. fireSparrow
                  15.03.2024 06:57
                  +1

                  >> в бестиповом языке

                  Вот только в питоне строгая типизация.


              1. ednersky
                15.03.2024 06:57

                И типы, внезапно, нужны не только для того, чтобы сделать счастливым
                компилятор.

                только для этого

                А ещё и для того, чтобы сделать работу программиста проще и сократить число ошибок.

                каким же образом эта работа становится проще, если вместо строки кода программист должен писать экраны?


                1. fireSparrow
                  15.03.2024 06:57
                  +1

                  Вы когда-нибудь занимались поддержкой проекта на 100000+ строк, в который два десятка программистов несколько лет писали?

                  Я бы посмотрел, как вы это будете без типов делать.


                  1. ednersky
                    15.03.2024 06:57

                    ага

                    занимался

                    а потом занимался проектами с типами

                    так вот с последними гемора куда больше


                    1. gromyko21 Автор
                      15.03.2024 06:57
                      +1

                      Расскажи в чем конкретно был гемор? Неправильно определили типы?


                      1. ednersky
                        15.03.2024 06:57

                        гемор в том, что вместо решения проблем проекта масса времени тратится на работу с типами

                        это как пытаться bash заменить на С++

                        на bash 4 строки

                        на С++ 4 модуля, плюс система сборки, компилятор итп

                        конечно bash vs C++ это предельный кейс, но именно он показывает никчемность, ненужность типов

                        Вы когда-нибудь занимались поддержкой проекта на 100000+

                        вы когда-нибудь задумывались, что цифра 100000+ может быть сокращена впятеро-десятеро простым отказом от типов?


                      1. gromyko21 Автор
                        15.03.2024 06:57
                        +1

                        Я, в случае, если метод принимает 3+ аргумента сразу разному каждый из них на новую строку, для лучшей читаемости, а рядом ставлю тип, что никак не увеличивает количество строк.

                        Если говорить про 1-2 аргумента - оставляю их на одной строке и на ней же добавляю типы, что так же никак не увеличивает количество строк.


                      1. fireSparrow
                        15.03.2024 06:57

                        del, не туда ответил


                      1. fireSparrow
                        15.03.2024 06:57
                        +3

                        Я не знаю, что у вас за специфичный проект такой был.

                        В моей практике большинство проектов пишутся за достаточно небольшой период времени, а потом годы занимает их поддержка и доработка. И поэтому основную часть времени разработчик читает код, а не пишет. В таком режиме хорошо расставленные типы могут сократить затраченное разработчиком время в десятки раз. И значительно сократить количество багов при изменении существующего кода.

                        Ну и расстановка типов не увеличивает как-то драматически ни объём кода, ни затраченное время на его написание.Уж точно не в разы, даже если сказать, что на 10% - то это достаточно пессимистичная оценка.


                      1. ednersky
                        15.03.2024 06:57

                        И поэтому основную часть времени разработчик читает код, а не пишет.

                        Именно так. и потому за типы, за необоснованный ООП, за рекурсии, и за многое другое прямо бить по рукам иногда хочется.


                      1. fireSparrow
                        15.03.2024 06:57
                        +1

                        >> за необоснованный ООП

                        За необоснованное что угодно можно бить по рукам.

                        Но при правильном использовании и ООП, и типы, облегчают работу с кодом, а не усложняют. Если у вас типы и ООП только мешают - то либо вы работаете с какими совсем уж специфичными кейсами, либо вы просто не умеете их готовить.


                      1. ednersky
                        15.03.2024 06:57

                        ООП в 95% случаев оказывается необоснован

                        типы необоснованы в 100% случаев, где решение на скриптовом языке возможно


      1. ednersky
        15.03.2024 06:57

        Поддерживать код, у которого не размечены типы - очень-очень больно.

        поддерживать код, у которого они размечены, куда больнее!

        ибо там где без типов 3 строки кода, с типами получается 3 экрана

        ведь что Вы предлагаете?

        вместо вызова функции сперва вызывать функции-конструкторы датасетов, которые станут аргументами функции

        а эти конструкторы тоже через датасеты?

        Бр-р-р!


        1. fireSparrow
          15.03.2024 06:57

          В питоне для датаклассов обычно не используются какие-то отдельные функции конструкторы. А само по себе инстанцирование датакласса занимает примерно столько же места, сколько и создание словаря.


      1. Andrey_Solomatin
        15.03.2024 06:57

        Это больше похоже на плохую архитектуру, язык здесь вторичен.

        Мапы объектов можно и в типизированных языках передавать.

        Если нет требования по производительности, просто делайте всё неизменяемым и создавайте обхект нового типа на каждной стадии. Если нет, то паттерн строитель.

        Датаклассы не очень помогут, Any | None поменятеся на int | None и поля будут определены. Если вы не можете посчитать состояния объекта по пальцам одной руки, это уже сложно для восприятия. Два optional поля дают 4 варианта состояния. None(еще на заполнен) и None(Заплненное значение) это два разных стостояния, но из вообще не отличить.


  1. longclaps
    15.03.2024 06:57

    С момента создания питона разработчики языков додумались, удивительное дело, в статически типизированных языках типа Kotlin выводить тип переменной из вида (написания) присваемого значения. Меньше синтаксического мусора, почти как в питоне).

    Вольное присваивание аргументам функций в питоне значений произвольного типа - это удобное решение для скриптовых языков. В котлине сходной гибкости и выразительности добиваются созданием нескольких одноименных функций с разной сигнатурой, но писанины больше. Аннотирование функций в питоне подравнивает ситуацию по объёму писанины, но котлином его не делает, в смысле строгости и производительности. Так что присоединяюсь к автору статьи: хочешь типов - присмотрись к другим языкам.


    1. Andrey_Solomatin
      15.03.2024 06:57

      Аннотирование функций в питоне подравнивает ситуацию по объёму писанины


      Это в простых случаях. А в сложных в Питоне просто забиваешь и работает, а в статических языках придётся решать. А там это делать куда сложнее.


      1. gromyko21 Автор
        15.03.2024 06:57

        Сложнее и дольше - да. Но на действительно больших проектах это будет работать стабильнее)


  1. Sap_ru
    15.03.2024 06:57
    +2

    А ничего, что это все пришло из C/C++, где можно перегружать функции почти произвольным образом? Правда поломать совсем всё не даст жёсткая типизация. Проблема вовсе не в том, что можно обсудить функции с разной сигнатурой, но одним именем. Котлин тут отстаёт. Проблема в слабой типизации. А у Python еще и в, что перегрузка сделана через такие же костыли, что и все остальные типы, и реализация таких функции ведёт к небходимости избегать строгой проверки типов и куче трудно уловимых ошибок.


    1. tenzink
      15.03.2024 06:57

      У python всё-таки типизация сильная (нельзя сложить яблоки со столами), но динамическая. То есть до момента выполнения в общем случае вы не знаете точно пытаетесь ли складывать яблоки со столами


      1. Sap_ru
        15.03.2024 06:57

        То, что программа закрашится, это (наверное) хорошо. Но она откомпилируется и запустится. И может даже пройти все тесты, а закрашиться потом в самый неподходящий момент. Особенно актуально для перегрузки функций, где весь лоск немедленно слетает и заход солнца программист неизменно выполняет вручную.


        1. tenzink
          15.03.2024 06:57

          Именно поэтому предпочитаю писать на языках со статической типизацией, чтобы компилятор бил по рукам. Да и в python я бы предпочёл статическую типизацию, если бы она там была


          1. gromyko21 Автор
            15.03.2024 06:57

            Если бы она тут была - это был бы уже не python)


            1. tenzink
              15.03.2024 06:57

              Безусловно, это был бы другой язык с которым было бы интересно поработать. Всё равно я продумываю данные и типы и мой прикладной python код скорее всего отлично бы ложился на статическую типизацию


    1. Andrey_Solomatin
      15.03.2024 06:57

      Проблема в слабой типизации.


      В Питоне сильная типизация. А еще она динамическая.


  1. redfox0
    15.03.2024 06:57

    К сожалению, в Python типизация не дает никакого прироста производительности, а только потенциальное замедление и увеличение потребления памяти.

    Файлы *.pyi решают проблему "потенциального замедления и увеличения потребления памяти" и можно писать аннотаций сколько хочешь.

    Код картинками жгёт. Проверил, аннотации не вырезаются из оптимизированного кода, в отличии от __doc__ и assert.

    # python3 -OOO file.py
    def custom_sum(first: int, second: int) -> int:
        return first + second
        
    print(custom_sum.__annotations__)
    


    1. gromyko21 Автор
      15.03.2024 06:57

      Спасибо про замечание с кодом с картинками. Это моя первая подобная статья и я вообще не подумал, что их можно вставлять в виде текста и так будет комфортнее читать.


    1. fireSparrow
      15.03.2024 06:57

      Ну, логично, что аннотации не вырезаются.

      Ведь они являются полноценным атрибутом, и программист вполне может завязать какую-то логику на проверку аннотаций функции. Было бы странно, если бы оптимизация ломала такую логику.


      1. gromyko21 Автор
        15.03.2024 06:57

        Да, тот же FastApi завязан на них


    1. ednersky
      15.03.2024 06:57

      `print(custom_sum(1.5, 2.7))`

      `print(custom_sum("привет", "медвед"))`


  1. Vindicar
    15.03.2024 06:57

    Я воспринимаю аннотации типов скорее как декларативное описание "что в этом параметре/этой переменной". Условно, код на C-подобном языке float speed содержит описание типа, но не содержит сведения о том, как это значение интерпретировать - как метры в секунду или как километры в час. Тут ближе подходит концепция доменных типов, конечно - но аннотации в питоне являются приемлемым промежуточным решением, и позволяют добиться хоть какой-то ясности, не трогая саму логику.

    Что касается вышеупомянутой проблемы со словарями - есть TypedDict, который позволяет, по сути, описать схему для словаря (по аналогии со схемой JSON).


  1. vilgeforce
    15.03.2024 06:57

    " типы из библиотеки typing по типу List " - в более современных версиях питона list - встроенный тип и его не надо испортировать из typing, как и dict


    1. gromyko21 Автор
      15.03.2024 06:57

      Есть такое) С модулем typing, как по мне получился более выразительный пример. Хорошо, что не останавливался на этом вопросе, а решил его опустить


      1. NN1
        15.03.2024 06:57
        +1

        Типы из typing потихоньку переходят в разряд устаревших.

        Новые типы имеют поддержку в рантайме позволяя получить полный тип list[int] вместо List.

        https://docs.python.org/3/library/typing.html#deprecated-aliases


        1. Andrey_Solomatin
          15.03.2024 06:57

          Кроме  коллкеций который переехали, там есть и другие вещи.

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


          1. NN1
            15.03.2024 06:57

            Если есть 3.9 и выше, а скорее всего так уже и есть, стоит использовать новые аннотации вместо устаревших.


  1. NN1
    15.03.2024 06:57

    По умолчанию у MyPy довольно щадящие настройки.

    https://careers.wolt.com/en/blog/tech/professional-grade-mypy-configuration

    Можно немного сделать строже.


  1. Andrey_Solomatin
    15.03.2024 06:57

    Можно видеть проблему “опережающей ссылки”.  Наш класс в одном из
    методов хочет вернуть экземпляр самого себя, но не сможет этого сделать,
    поскольку объект класса еще не определен, пока Python не закончит
    вычисление его тела. В этом случае мы вынуждены записать возвращаемое
    значение в виде строки.


    Приветствую тебя гость из прошлого.

    В 3.9 можно вот так:

    from __future__ import annotations

    https://peps.python.org/pep-0563/


    1. omaxx
      15.03.2024 06:57

      Вы поспешили написать этот комментарий до того как прочли следующий абзац?

      Одобренный PEP 563 “Postponed Evaluation of Annotations” уменьшил время необходимое для обработки аннотаций типов во время выполнения. Аннотации типов больше не вычисляются в момент определения функции, вместо этого они сохраняются в аннотациях в строковой форме(не производя никаких вычислений). Чтобы достичь этого нужно сделать один import


      1. Andrey_Solomatin
        15.03.2024 06:57

        Да, только проверил дату публикации.

        Убирать не стал, так как второй обзац сфокусирован на другой проблеме и про что он решает "опережающей ссылки" нужно самому додуматься.

        Посмотрел доку, а этот PEP до сих пор не включили в Питон.

        Я его перепутал с https://peps.python.org/pep-0604/ которого мне в 3.9 не хватет.