Qual é o significado do atributo __total__ dunder no Python 3?

17

No recém-lançado Python 3.8, há uma nova anotação de tipo typing.TypedDict. Sua documentação menciona que

As informações de tipo para introspecção podem ser acessadas via Point2D.__annotations__e Point2D.__total__. [....]

Embora __annotations__seja bem conhecido, tendo sido introduzido no PEP 3107 , não consigo encontrar nenhuma informação sobre __total__. Alguém poderia explicar seu significado e, se possível, vincular-se a fontes autorizadas?

Antti Haapala
fonte
4
Típica. 99% dos typinginternos não estão documentados e a parte que está documentada é mal.
Aran-Fey

Respostas:

3

Suponho que o __total__campo signifique se as instâncias devem ser completas (o padrão) ou não (todos os campos são opcionais). Comecei minha pesquisa no PEP 589 , que introduziu TypedDicte descreve a totalidade como tal. Ele usou um totalargumento, no qual faria sentido renomear o estilo dunder para a class sintaxe. No entanto, não encontrei quando essa renomeação ocorreu.

Examinando o MyPy, que é o verificador real de tipos que se preocupa com essas anotações, há documentação TypedDicte totalidade semelhantes , mas novamente nenhuma referência à sintaxe do dunder. Cavar na sua implementação levou a mais confusão, como TypedDictTypeno types.py não tem um campo total, mas separado itemse required_keys. A totalidade implicaria isso, items.keys()==required_keysmas a implementação faz suposições diferentes, como can_be_falseconfiar itemssozinho. total=Falseem princípio, significa que required_keysestá vazio.

A fonte CPython para _TypedDictMeta pelo menos revela que o totalargumento e o __total__dunder são o mesmo, embora a fonte se descreva TypedDictcomo "possa ser adicionada em breve".

Yann Vernier
fonte
Aceitando isso por enquanto - se não houver mais nada, talvez isso torne os outros mais dispostos a se apresentar e refutar sua resposta: D
Antti Haapala
Pessoalmente, suspeito que a can_be_falsecoisa seja um bug do MyPy, possivelmente relacionado a não ter planejado ter campos opcionais desde o início.
Yann Vernier
1

TypedDictfoi aceito no Python 3.8 via PEP 589 . No Python, parece __total__ser um sinalizador booleano definido como Truepadrão:

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

# <class 'bool'>
# True

Como mencionado em outras postagens, os detalhes sobre esse método são limitados nos documentos , mas o link de @Yann Vernier para o código-fonte CPython sugere fortemente que __total__está relacionado à nova totalpalavra-chave introduzida no 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
        ...

Como funciona?

Sinopse : por padrão, todas as chaves são necessárias ao instanciar um definido TypedDict. total=Falsesubstitui essa restrição e permite chaves opcionais. Veja a seguinte demonstração.

Dado

Uma árvore de diretórios de teste:

insira a descrição da imagem aqui

Código

Arquivos no diretório de teste:

# 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"

Demo

Se uma chave estiver faltando, o mypy irá reclamar na linha de comando:

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

A configuração total=Falsepermite chaves opcionais:

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

Veja também

pylang
fonte