Что означает атрибут __total__ dunder в Python 3? - PullRequest
16 голосов
/ 17 октября 2019

В недавно выпущенном Python 3.8 появилась новая аннотация типа typing.TypedDict. В документации упоминается, что

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

Хотя __annotations__ хорошо известно, оно было введено в PEP 3107 , но я не могу найти никакой информации по __total__. Может ли кто-нибудь объяснить его значение и, если возможно, ссылки на авторитетные источники?

Ответы [ 2 ]

3 голосов
/ 17 октября 2019

Я предполагаю, что поле __total__ указывает, должны ли экземпляры быть полными (по умолчанию) или нет (все поля необязательны). Я начал свой поиск с PEP 589 , который ввел TypedDict и описывает совокупность как таковую. В нем использовался аргумент total, который имел бы смысл переименовать в стиле dunder для синтаксиса class. Однако я не нашел, когда произошло такое переименование.

Рассматривая MyPy, которая является средством проверки типов, которое заботится об этих аннотациях, есть аналогичная документация по TypedDict и совокупности , но опять же нет ссылки на синтаксис dunder. Копание в его реализации привело к еще большей путанице, поскольку TypedDictType в types.py не имеет общего поля, а разделяет items и required_keys. Совокупность подразумевает, что items.keys()==required_keys, но реализация делает другие предположения, например, can_be_false, опираясь только на items. total=False в принципе означает, что required_keys пусто.

Исходный код CPython для _TypedDictMeta по крайней мере показывает, что аргумент total и __total__ dunder - одно и то же, хотя источник описывает сам TypedDict как ", может быть добавленскоро".

1 голос
/ 29 октября 2019

TypedDict был принят в Python 3.8 через PEP 589 . В Python __total__ является логическим флагом, установленным по умолчанию True:

tot = TypedDict.__total__
print(type(tot))
print(tot)

# <class 'bool'>
# True

Как упоминалось в других публикациях, подробности этого метода ограничены в документах , но ссылка @Yann Vernier на исходный код CPython настоятельно рекомендует __total__ связана с новым ключевым словом total , введенным в Python 3.8 :

# cypthon/typing.py

class _TypedDictMeta(type):
    def __new__(cls, name, bases, ns, total=True):
        """Create new typed dict class object.
        ...
        """
        ...
        if not hasattr(tp_dict, '__total__'):
            tp_dict.__total__ = total
        ...

Как это работает?

Конспект : по умолчанию все ключи требуются при создании экземпляра определенного TypedDict. total=False отменяет это ограничение и разрешает дополнительные ключи. См. Следующую демонстрацию.

Дано

Тестовое дерево каталогов:

enter image description here

Код

Файлы в тестовом каталоге:

# rgb_bad.py

from typing import TypedDict


class Color(TypedDict):
    r: int
    g: int
    b: int
    a: float


blue = Color(r=0, g=0, b=255)                     # missing "a"

# rgb_good.py

from typing import TypedDict


class Color(TypedDict, total=False):
    r: int
    g: int
    b: int
    a: float


blue = Color(r=0, g=0, b=255)                     # missing "a"

Демо

Если ключ отсутствует, mypy будет жаловаться на командную строку:

> mypy code/rgb_bad.py
code\rgb_bad.py:11: error: Key 'a' missing for TypedDict "Color"
...

Установка total=False разрешает дополнительные ключи:

> mypy code/rgb_good.py
Success: no issues found in 1 source file

См. Также

...