web-dev-qa-db-fra.com

Quelle est la signification de l'attribut __total__ dunder dans Python 3?

Dans la nouvelle version Python 3.8 il y a une nouvelle annotation de type typing.TypedDict . Sa documentation mentionne que

Les informations de type pour l'introspection sont accessibles via Point2D.__annotations__ et Point2D.__total__. [....]

Tandis que __annotations__ est bien connu, ayant été introduit dans PEP 3107 , je ne trouve aucune information sur __total__. Quelqu'un pourrait-il expliquer sa signification et si possible un lien vers des sources faisant autorité?

17
Antti Haapala

Je suppose que le champ __total__ Signifie si les instances doivent être complètes (par défaut) ou non (tous les champs facultatifs). J'ai commencé ma recherche à PEP 589 , qui a introduit TypedDict et décrit la totalité comme telle. Il a utilisé un argument total, qu'il serait judicieux de renommer dunder-style pour la syntaxe class. Cependant, je n'ai pas trouvé quand un tel changement de nom a eu lieu.

En examinant MyPy, qui est le vérificateur de type réel qui se soucie de ces annotations, il y a documentation similaire sur TypedDict et la totalité , mais encore une fois aucune référence à la syntaxe dunder. Creuser dans son implémentation a conduit à plus de confusion, car TypedDictType dans types.py n'a pas de champ total, mais séparé items et required_keys . La totalité impliquerait que items.keys()==required_keys mais l'implémentation fait des hypothèses différentes, telles que can_be_false Reposant uniquement sur items. total=False Devrait en principe signifier que required_keys Est vide.

La source CPython pour _ TypedDictMeta révèle au moins que l'argument total et __total__ Dunder sont une seule et même chose, bien que la source se décrit TypedDict elle-même comme msgstr "peut être ajouté bientôt".

3
Yann Vernier

TypedDict a été accepté dans Python 3.8 via PEP 589 . À partir de Python, il apparaît __total__ est un indicateur booléen défini sur True par défaut:

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

# <class 'bool'>
# True

Comme mentionné dans d'autres articles, les détails de cette méthode sont limités dans le docs , mais le lien de @Yann Vernier vers le code source CPython suggère fortement __total__ est lié au nouveau mot clé totalintroduit dans 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
        ...

Comment ça marche?

Synopsis: par défaut, toutes les clés sont requises lors de l'instanciation d'un TypedDict défini. total=False remplace cette restriction et autorise les clés facultatives. Voir la démonstration suivante.

Étant donné

Une arborescence de répertoires de test:

enter image description here

Code

Fichiers dans le répertoire de test:

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

Démo

Si une clé est manquante, mypy se plaindra à la ligne de commande:

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

Réglage total=False autorise les clés optionnelles:

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

Voir aussi

  • Tweet par R. Hettinger démontrant la totalité
  • PEP section sur la totalité en PEP 589
  • Article Section sur les types et TypedDict dans Python 3.8 par Real Python
  • typing-extensions package pour utiliser TypedDict in Python 3.5, 3.6
1
pylang