Что такое аннотации переменных?

Скоро будет выпущен Python 3.6. PEP 494 - Расписание выпусков Python 3.6 упоминает конец декабря, поэтому я просмотрел Что нового в Python 3.6, чтобы увидеть, что они упоминают аннотации переменных :

PEP 484 представил стандарт для аннотаций типов параметров функций, также известных как подсказки типов. Этот PEP добавляет синтаксис к Python для аннотирования типов переменных, включая переменные класса и переменные экземпляра:

primes: List[int] = []

captain: str  # Note: no initial value!

class Starship:
     stats: Dict[str, int] = {}

Как и в случае с аннотациями функций, интерпретатор Python не придает никакого особого значения аннотациям переменных, а только сохраняет их в специальном атрибуте __annotations__ класса или модуля. В отличие от объявлений переменных в статически типизированных языках, цель синтаксиса аннотаций - предоставить простой способ указать метаданные структурированного типа для сторонних инструментов и библиотек с помощью абстрактного синтаксического дерева и атрибута __annotations__.

Итак, из того, что я прочитал, они являются частью подсказок типов, поступающих из Python 3.5, описанных в Что такое подсказки типов в Python 3.5 .

Я следую примерам captain: str и class Starship, но не уверен насчет последнего: как primes: List[int] = [] объясняет? Это определение пустого списка, который разрешает только целые числа?


person fedorqui 'SO stop harming'    schedule 11.10.2016    source источник
comment
Подсказки типа не проверяют тип. primes: List[int] = [] - это просто пустой список как primes = []. Разница в том, что вы утверждаете, что primes должен содержать только ints, и сторонние приложения могут ввести проверку вашей программы, чтобы проверить это утверждение, но когда вы запустите код в любой интерпретатор Python, аналогичный записи primes = [], и, таким образом, выполнение primes: List[int] = []; primes.append("string") по-прежнему действителен.   -  person Bakuriu    schedule 11.10.2016
comment
@Bakuriu Да, хорошее замечание. Как описывает Джим Фасаракис-Хиллиард в своем ответе на вопрос Что такое подсказки типа в Python 3.5, почему подсказки типа Помогает средствам проверки типов, помогает с документацией и помогает IDE разрабатывать более точные и надежные инструменты. Взято из PEP 526 - синтаксис для аннотаций переменных, Python останется языком с динамической типизацией, и у авторов нет желания когда-либо делать подсказки типов обязательными, даже по соглашению.   -  person fedorqui 'SO stop harming'    schedule 11.10.2016
comment
Отвечает ли это на ваш вопрос? Что такое подсказки типов в Python 3.5?   -  person AMC    schedule 15.04.2020


Ответы (2)


Все между : и = является подсказкой типа, поэтому primes действительно определен как List[int] и изначально установлен в пустой список (а stats - это изначально пустой словарь, определенный как Dict[str, int]).

List[int] и Dict[str, int] не являются частью следующего синтаксиса, однако они уже были определены в подсказках ввода Python 3.5 PEP. Только предложение PEP 526 - синтаксис для аннотаций переменных 3.6. определяет синтаксис для добавления одинаковых подсказок к переменным; раньше вы могли только присоединять подсказки типа к переменным с комментариями (например, primes = [] # List[int]).

Оба List и Dict являются универсальными типами, что указывает на то, что у вас есть сопоставление списка или словаря с определенным (конкретным) содержимым.

Для List существует только один «аргумент» (элементы в синтаксисе [...]), тип каждого элемента в списке. Для Dict первый аргумент - это тип ключа, а второй - тип значения. Итак, все значения в списке primes являются целыми числами, а все пары "ключ-значение" в stats словаре - это пары (str, int), отображающие строки в целые числа.

См. typing.List и typing.Dict определений, раздел на Generics, а также PEP 483 - Theory of Type Подсказки.

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

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

person Martijn Pieters    schedule 11.10.2016
comment
Могу ли я рассматривать подсказки типа как своего рода машиночитаемые комментарии, поскольку они не влияют на работу кода (за исключением атрибута obj.__annotations__)? - person iBug; 27.09.2018
comment
@iBug: аннотации - это машиночитаемые комментарии, поскольку комментарии в любом случае являются удобочитаемыми аннотациями. :-) - person Martijn Pieters; 27.09.2018

Что такое аннотации переменных?

Аннотации переменных - это всего лишь следующий шаг от комментариев # type, как они были определены в PEP 484; обоснование этого изменения выделено в соответствующем разделе PEP 526 .

Итак, вместо того, чтобы указывать тип с помощью:

primes = []  # type: List[int]

Был введен новый синтаксис, позволяющий напрямую аннотировать тип с помощью присвоения формы:

primes: List[int] = []

который, как указал @Martijn, обозначает список целых чисел с использованием типов, доступных в _5 _ и инициализируя его пустым списком.

Какие изменения это принесет?

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

annotated_assignment_stmt ::=  augtarget ":" expression ["=" expression]

Итак, рассматриваемый пример:

   primes: List[int] = [ ]
#    ^        ^         ^
#  augtarget  |         |
#         expression    |
#                  expression (optionally initialize to empty list)

Вместе с новым синтаксисом были также внесены дополнительные изменения; модули и классы теперь имеют атрибут __annotations__ (как и функции с PEP 3107 - - Аннотации функций), к которым прикреплены метаданные типа:

from typing import get_type_hints  # grabs __annotations__

Теперь __main__.__annotations__ содержит объявленные типы:

>>> from typing import List, get_type_hints
>>> primes: List[int] = []
>>> captain: str
>>> import __main__
>>> get_type_hints(__main__)
{'primes': typing.List<~T>[int]}

captain в настоящее время не отображается через get_type_hints, поскольку возвращает только get_type_hints типы, к которым также можно получить доступ в модуле; т.е. ему сначала нужно значение:

>>> captain = "Picard"
>>> get_type_hints(__main__)
{'primes': typing.List<~T>[int], 'captain': <class 'str'>}

Использование print(__annotations__) покажет 'captain': <class 'str'>, но вам действительно не следует обращаться к __annotations__ напрямую.

Аналогично для классов:

>>> get_type_hints(Starship)
ChainMap({'stats': typing.Dict<~KT, ~VT>[str, int]}, {})

Где ChainMap используется для захвата аннотаций для данного класса (расположенного в первом сопоставлении) и всех аннотаций, определенных в базовых классах, найденных в его mro (последующие сопоставления, {} для объекта).

Наряду с новым синтаксисом был добавлен новый тип ClassVar для обозначения переменных класса. Ага, stats в вашем примере на самом деле является переменной экземпляра, а не ClassVar.

Меня заставят его использовать?

Как и подсказки типа из PEP 484, они полностью необязательны и в основном используются для инструментов проверки типов (и всего, что вы можете создать на основе этой информации). Он будет временным, когда выйдет стабильная версия Python 3.6, поэтому в будущем могут быть добавлены небольшие изменения.

person Dimitris Fasarakis Hilliard    schedule 11.10.2016
comment
Ситуация немного изменилась в Python 3.9+ с введением PEP 585. . Это изменило ваш пример на primes: list[int] = [] или даже проще primes = list[int](). - person Jeyekomon; 25.06.2021