Что такое переменные аннотации в 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] = []
? Является ли он определением пустого списка, который будет просто использовать целые числа?
Ответы
Ответ 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 выпущена, поэтому в будущем могут быть добавлены небольшие настройки.