Что такое переменные аннотации в Python 3.6? - программирование

Что такое переменные аннотации в Python 3.6?

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

PEP 484 представил стандарт аннотаций типа параметров функции, подсказки типа a.k.a. Этот 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] = []? Является ли он определением пустого списка, который будет просто использовать целые числа?

4b9b3361

Ответ 1

Все между : и = является подсказкой типа, поэтому 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, в разделе Generics, а также PEP 483 - Теория типов подсказок.

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

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

Ответ 2

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

Переменные аннотации - это всего лишь следующий шаг от комментариев # 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 - 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. Yup, stats в вашем примере на самом деле является переменной экземпляра, а не ClassVar.

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

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