Сообщить об ошибке.

Аннотации типов в Python

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

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

В следующем примере есть позиционный аргумент, ключевой аргумент и аннотированное возвращаемое значение:

>>> def f(ham: str, eggs: str = 'eggs') -> str:
...     print("Annotations:", f.__annotations__)
...     print("Arguments:", ham, eggs)
...     return ham + ' and ' + eggs
...
>>> f('spam')
# Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>}
# Arguments: spam eggs
# 'spam and eggs'
>>>

Основы аннотаций.

Прежде чем обсуждать аннотации функций в Python 3, сначала надо понять, что такое аннотации:

  • Для аннотаций сложных или пользовательских типов переменных необходимо использовать встроенный модуль typing.
  • Аннотации в функции, как для параметров, так и для возвращаемых значений, являются полностью необязательными.
  • Аннотации функций - не более чем способ связывания произвольных выражений Python с различными частями функции во время компиляции.

    Сам по себе Python не придает никакого особого значения аннотациям. Python просто делает эти выражения доступными, как описано в разделе "Доступ к аннотациям".

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

    def compile (source: "something compilable",
                filename: "where the compilable thing comes from",
                mode: "is this a single statement or a suite?"):
        ...
    

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

    def haul(item: Haulable, *vargs: PackAnimal) -> Distance:
        ...
    

    Однако ни строки в первом примере, ни информация о типе во втором примере сами по себе не имеют никакого значения, смысл исходит только от сторонних библиотек.

  • Аннотации не пытаются вводить какую-либо стандартную семантику, даже для встроенных типов. Эта работа будет предоставлена ​​сторонним модулям.

Синтаксис.

Параметры:

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

def foo (a: expression, b: expression = 5):
    ...

В псевдограмматике параметры теперь выглядят как идентификатор [: expression] [= expression]. То есть аннотации всегда предшествуют значению параметра по умолчанию, а аннотации и значения по умолчанию являются необязательными. Также как знаки равенства используются для обозначения значения по умолчанию, двоеточия используются для пометки аннотаций. Все выражения аннотаций оцениваются при выполнении определения функции, как и значения по умолчанию.

Аннотации для избыточных параметров (например, *args и **kwargs ) указываются аналогично:

def foo(*args: expression, **kwargs: expression):
    ...

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

def foo((x1, y1: expression),
        (x2: expression, y2: expression)=(None, None)):
    ...

Возвращаемые значения:

До сих пор в примерах отсутствовали примеры того, как аннотировать тип возвращаемого значения функции. Это делается так:

def sum() -> expression:
    ...

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

Синтаксис lambda-функций не поддерживает аннотации.

Новое в Python 3.9

В аннотациях типов теперь можно использовать встроенные типы, такие как list и dict, в качестве универсальных типов вместо импорта соответствующих типов из модуля аннотации типов typing (например, typing.List или typing.Dict).

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

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

>>> from typing import List, Dict
>>> List[int]
# typing.List[int]
>>> Dict[str, int]
# typing.Dict[str, int]

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

>>> list[int]
# <class 'list'>
>>> tuple[int]
# <class 'tuple'>

В функциях или классах они могут выглядеть следующим образом:

def greet_all(names: list[str]) -> None:
    for name in names:
        print("Hello", name)

Доступ к аннотациям.

После компиляции, аннотации функции становятся доступны через атрибут функции __annotations__. Этот атрибут представляет собой изменяемый словарь, отображающий имена параметров в объекте, представляющий оценочное выражение аннотации.

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

Например, следующая аннотация:

def foo (a: 'x', b: 5 + 6, c: list) -> max(2, 9):
    ...

приведет к отображению __annotations__

{'a': 'x',
 'b': 11,
 'c': list,
 'return': 9}

Ключ возврата был выбран потому, что он не может конфликтовать с именем параметра. Любая попытка использовать return в качестве имени параметра приведет к SyntaxError .

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