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

Тип аннотации TypedDict() модуля typing в Python

Добавление аннотаций типов в словарь

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

Синтаксис:

from typing import TypedDict

# Новое в Python 3.8.
TypedDict(dict)

Параметры:

  • dict - словарь.

Описание:

Тип аннотации TypedDict() модуля typing представляет собой специальную конструкцию для добавления аннотаций типов в словарь. Во время выполнения это простой словарь dict.

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

Применение:

from typing import TypedDict

class Point2D(TypedDict):
    x: int
    y: int
    label: str

# Проверка проходит
a: Point2D = {'x': 1, 'y': 2, 'label': 'good'}
# Не удается проверить тип
b: Point2D = {'z': 3, 'label': 'bad'}

assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')

Информация о типе для интроспекции может быть доступна через Point2D.__ annotations__ и Point2D.__total__.

Чтобы разрешить использование этой функции со старыми версиями Python, тип аннотации TypedDict поддерживает две дополнительные эквивалентные синтаксические формы:

# Использование буквального словаря в качестве второго аргумента:
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
# Использование ключевых аргументов:
Point2D = TypedDict('Point2D', x=int, y=int, label=str)

Синтаксис ключевых аргументов устарел начиная с Python 3.11, будет удален в Python 3.13. Он также может не поддерживаться средствами проверки статических типов.

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

from typing import TypedDict

# вызывает синтаксическую ошибку
class Point2D(TypedDict):
    in: int  # 'in' - это ключевое слово
    x-y: int  # имя с дефисами

# OK
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})

По умолчанию все ключи должны присутствовать в TypedDict. Отдельные ключи можно пометить как необязательные с помощью typing.NotRequired:

from typing import TypedDict, NotRequired

class Point2D(TypedDict):
    x: int
    y: int
    label: NotRequired[str]

# Альтернативный синтаксис
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': NotRequired[str]})

Это означает, что в Point2D() в TypedDict ключ label может быть опущен.

Также можно пометить все ключи как необязательные по умолчанию, указав в совокупности значение False:

from typing import TypedDict

class Point2D(TypedDict, total=False):
    x: int
    y: int

# Alternative syntax
Point2D = TypedDict('Point2D', {'x': int, 'y': int}, total=False)

Это означает, что в Point2D, TypedDict любой из ключей может быть опущен. Ожидается, что средство проверки типов будет поддерживать только литерал False или True в качестве значения общего аргумента. True - это значение по умолчанию, которое делает обязательными все элементы, определенные в теле класса.

Отдельные ключи total=False в TypedDict могут быть помечены как требуемые с помощью typing.Required:

from typing import TypedDict, Required

class Point2D(TypedDict, total=False):
    x: Required[int]
    y: Required[int]
    label: str

# Альтернативный синтаксис
Point2D = TypedDict('Point2D', {
    'x': Required[int],
    'y': Required[int],
    'label': str
}, total=False)

Тип typing.TypedDict может наследовать от одного или нескольких других типов TypedDict, используя синтаксис на основе классов.

Применение:

class Point3D(Point2D):
    z: int

Класс Point3D имеет три элемента: x, y и z. Это эквивалентно этому определению:

from typing import TypedDict

class Point3D(TypedDict):
    x: int
    y: int
    z: int

typing.TypedDict не может наследовать от класса, отличного от TypedDict, за исключением typing.Generic. Например:

from typing import TypedDict, Generic, TypeVar

class X(TypedDict):
    x: int

class Y(TypedDict):
    y: int

# Класс без TypedDict
class Z(object): pass

# Проходит проверку
class XY(X, Y): pass

# вызывает ошибку типа
class XZ(X, Z): pass

T = TypeVar('T')

# вызывает TypeError
class XT(X, Generic[T]): pass

TypedDict может быть общим:

from typing import TypedDict, Generic

class Group(TypedDict, Generic[T]):
    key: T
    group: list[T]

typing.TypedDict может быть универсальным:

class Group[T](TypedDict):
    key: T
    group: list[T]

Чтобы создать универсальный TypedDict, совместимый с Python 3.11 или более ранней версии, явно наследуйте от Generic:

T = TypeVar("T")

class Group(TypedDict, Generic[T]):
    key: T
    group: list[T]

Класс typing.TypedDict можно проанализировать с помощью словарных аннотаций, __total__, __required_keys__ и __optional_keys__.

__total__:

Point2D.__total__ возвращает значение общего аргумента. Пример:

>>> from typing import TypedDict
>>> class Point2D(TypedDict): pass
>>> Point2D.__total__
# True
>>> class Point2D(TypedDict, total=False): pass
>>> Point2D.__total__
# False
>>> class Point3D(Point2D): pass
>>> Point3D.__total__
# True

Этот атрибут отражает только значение общего аргумента текущего класса TypedDict, а не то, является ли класс семантически полным. Например, TypedDict с __total__, установленным в True, может иметь ключи, отмеченные NotRequired, или он может наследовать от другого TypedDict с total=False. Поэтому для самоанализа обычно лучше использовать __required_keys__ и __optional_keys__.

__required_keys__:
__optional_keys__:

Новое в Python 3.9.

Point2D.__required_keys__ и Point2D.__optional_keys__ возвращают frozenset объекты, содержащие обязательные и необязательные ключи соответственно.

Ключи, помеченные как "обязательные", всегда будут отображаться в __required_keys__, а ключи, отмеченные как "необязательные", всегда будут отображаться в __optional_keys__.

Для обратной совместимости с Python 3.10 и ниже также можно использовать наследование для объявления как обязательных, так и необязательных ключей в одном и том же TypedDict. Это делается путем объявления TypedDict с одним значением для итогового аргумента и последующего наследования от него другого TypedDict с другим значением для итогового значения:

class Point2D(TypedDict, total=False):
    x: int
    y: int

class Point3D(Point2D):
    z: int

>>> Point3D.__required_keys__ == frozenset({'z'})
# True
>>>Point3D.__optional_keys__ == frozenset({'x', 'y'})
# True

Примечание. Если используются аннотации импорта from __future__ или аннотации задаются в виде строк, то аннотации не оцениваются при определении TypedDict. Таким образом, самоанализ во время выполнения, на который полагаются __required_keys__ и __optional_keys__, может работать неправильно, а значения атрибутов могут быть неправильными.


Изменено в Python 3.11: добавлена ​​поддержка пометки отдельных ключей как Required или NotRequired.

Изменено в Python 3.11: Добавлена ​​поддержка общих TypedDict.