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

84

Готовится к выпуску 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] = []объяснить? Это определение пустого списка, который разрешает только целые числа?

fedorqui 'ТАК, хватит вредить'
источник
10
Тип намеки не не делать какие - либо проверки типов. primes: List[int] = []это просто пустой список как primes = []. Разница в том, что вы утверждаете, что primes оно предназначено для содержания только ints, и сторонние приложения могут ввести проверку вашей программы, чтобы проверить это утверждение, но когда вы запускаете код в любом интерпретаторе python, который точно такой же, как и запись primes = [], и, таким образом, выполнение primes: List[int] = []; primes.append("string")по-прежнему действительный.
Bakuriu
2
@Bakuriu Да, хорошее замечание. Как Джим Фасаракис-Хиллиард описывает в своем ответе на вопрос « Что такое подсказки типа в Python 3.5» , почему подсказки типовПомогают средствам проверки типов, помогают с документацией и помогают IDE разрабатывать более точные и надежные инструменты . Взято из PEP 526 - Синтаксис для аннотаций переменных , Python останется языком с динамической типизацией, и у авторов нет желания когда-либо делать подсказки типов обязательными, даже по соглашению .
fedorqui 'SO, перестань причинять вред'
1
Отвечает ли это на ваш вопрос? Что такое подсказки типов в Python 3.5?
AMC

Ответы:

48

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

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

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

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

Смотрите typing.Listи typing.Dictопределения, в раздел дженериков , а также PEP 483 - Теория типа подсказки .

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

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

Мартейн Питерс
источник
1
Могу ли я рассматривать подсказки типа как своего рода «машиночитаемые» комментарии, поскольку они не влияют на работу кода (кроме obj.__annotations__атрибута)?
iBug
2
@iBug: аннотации - это машиночитаемые комментарии, поскольку комментарии в любом случае являются удобочитаемыми аннотациями. :-)
Мартейн Питерс
59

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

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

Итак, вместо намека на тип с помощью:

primes = []  # type: List[int]

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

primes: List[int] = []

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

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

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

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

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

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

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

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]}, {})

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

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

Я буду вынужден его использовать?

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

Димитрис Фасаракис Хиллиард
источник