Co oznacza atrybut __total__ dunder w Pythonie 3?

17

W nowo wydanym Pythonie 3.8 dostępna jest adnotacja nowego typu typing.TypedDict. Dokumentacja wspomina o tym

Informacje o typie introspekcji można uzyskać za pomocą Point2D.__annotations__i Point2D.__total__. [....]

Chociaż __annotations__jest dobrze znany, po wprowadzeniu do PEP 3107 , nie mogę znaleźć żadnych informacji na jego temat __total__. Czy ktoś mógłby wyjaśnić jego znaczenie i, jeśli to możliwe, link do wiarygodnych źródeł?

Antti Haapala
źródło
4
Typowy. 99% elementów typingwewnętrznych nie jest udokumentowane, a część, która jest udokumentowana słabo.
Aran-Fey

Odpowiedzi:

3

Zgaduję, że __total__pole wskazuje, czy instancje muszą być kompletne (domyślne), czy nie (wszystkie pola opcjonalne). Rozpocząłem wyszukiwanie w PEP 589 , który wprowadził TypedDicti opisuje całość jako taką. Użył totalargumentu, który miałoby sens zmienić nazwę składni dla stylu dundera class . Nie znalazłem jednak, kiedy taka zmiana nazwy miała miejsce.

Patrząc na MyPy, który jest prawdziwym narzędziem do sprawdzania typów, który dba o te adnotacje, istnieje podobna dokumentacja TypedDicti całość , ale znowu nie ma odniesienia do składni dundera. Zagłębianie się w jego implementację doprowadziło do większej dezorientacji, ponieważ TypedDictTypew pliku types.py nie ma pola całkowitego, ale oddzielne itemsi required_keys. Totality implikuje to, items.keys()==required_keysale implementacja przyjmuje różne założenia, na przykład can_be_falsepoleganie itemswyłącznie na sobie. total=Falsepowinno w zasadzie oznaczać, że required_keysjest puste.

Źródło CPython dla _TypedDictMeta przynajmniej ujawnia, że totalargument i __total__dunder są jednym i tym samym, chociaż źródło opisuje TypedDictsię jako „może zostać dodane wkrótce”.

Yann Vernier
źródło
Zaakceptowanie tego na razie - jeśli nie cokolwiek innego, może sprawi, że inni będą bardziej skłonni do przedstawienia się i odrzucenia twojej odpowiedzi: D
Antti Haapala
Osobiście podejrzewam, że can_be_falsejest to błąd MyPy, prawdopodobnie związany z tym, że od początku nie planowałem mieć opcjonalnych pól.
Yann Vernier
1

TypedDictzostał zaakceptowany w Pythonie 3.8 przez PEP 589 . Z Python wygląda na __total__to, że flaga logiczna jest ustawiona Truedomyślnie na:

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

# <class 'bool'>
# True

Jak wspomniano w innych postach, szczegółowe informacje na temat tej metody są ograniczone w dokumentach , ale link @ Yanna Verniera do kodu źródłowego CPython zdecydowanie sugeruje, że __total__jest powiązany z nowym totalsłowem kluczowym wprowadzonym w Pythonie 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
        ...

Jak to działa?

Streszczenie : domyślnie wszystkie klucze są wymagane przy tworzeniu zdefiniowanej instancji TypedDict. total=Falsezastępuje to ograniczenie i zezwala na klucze opcjonalne. Zobacz następującą demonstrację.

Dany

Testowe drzewo katalogów:

wprowadź opis zdjęcia tutaj

Kod

Pliki w katalogu testowym:

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

Próbny

Jeśli brakuje klucza, mypy narzeka w wierszu poleceń:

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

Ustawienie total=Falsepozwala na opcjonalne klucze:

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

Zobacz też

  • Tweetuj R. Hettinger demonstrując całość
  • Sekcja PEP na temat całości w PEP 589
  • Sekcja artykułów na temat typów i TypedDictPython 3.8 autorstwa Real Python
  • typing-extensionspakiet do użycia TypedDictw Python 3.5, 3.6
pylang
źródło