¿Cuál es el significado del atributo __total__ dunder en Python 3?

17

En Python 3.8 recientemente lanzado hay una nueva anotación de tipo typing.TypedDict. Su documentación menciona que

Se puede acceder a la información de tipo para introspección a través de Point2D.__annotations__y Point2D.__total__. [....]

Si __annotations__bien es bien conocido, habiendo sido introducido en PEP 3107 , no puedo encontrar ninguna información sobre __total__. ¿Alguien podría explicar su significado y, si es posible, vincularlo a fuentes autorizadas?

Antti Haapala
fuente
44
Típico. El 99% de typinglas partes internas no está documentado, y la parte que sí está documentada de manera deficiente.
Aran-Fey

Respuestas:

3

Supongo que el __total__campo significa si las instancias deben estar completas (el valor predeterminado) o no (todos los campos son opcionales). Comencé mi búsqueda en PEP 589 , que introdujo TypedDicty describe la totalidad como tal. Usó un totalargumento, que tendría sentido cambiar el nombre de dunder-style por la class sintaxis. Sin embargo, no encontré cuándo tuvo lugar ese cambio de nombre.

Mirando a MyPy, que es el verificador de tipo real que se preocupa por estas anotaciones, hay documentación similar TypedDicty totalidad , pero nuevamente no hay referencia a la sintaxis de dunder. Profundizar en su implementación condujo a una mayor confusión, como TypedDictTypeen types.py no tiene un campo total, sino separado itemsy required_keys. La totalidad implicaría eso, items.keys()==required_keyspero la implementación hace suposiciones diferentes, como can_be_falseconfiar itemssolo. total=Falseen principio debería significar que required_keysestá vacío.

La fuente CPython para _TypedDictMeta al menos revela que el totalargumento y el __total__dunder son uno y el mismo, aunque la fuente se describe a TypedDictsí misma como "puede agregarse pronto".

Yann Vernier
fuente
Aceptando esto por ahora, si no otra cosa, tal vez hará que otros estén más dispuestos a presentarse y refutar su respuesta: D
Antti Haapala
Personalmente sospecho can_be_falseque se trata de un error de MyPy, posiblemente relacionado con no haber planeado tener campos opcionales desde el principio.
Yann Vernier
1

TypedDictfue aceptado en Python 3.8 a través de PEP 589 . Desde Python, parece que __total__es una bandera booleana configurada Truepor defecto:

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

# <class 'bool'>
# True

Como se mencionó en otras publicaciones, los detalles sobre este método están limitados en los documentos , pero el enlace de @Yann Vernier al código fuente de CPython sugiere que __total__está relacionado con la nueva totalpalabra clave introducida en 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?

Sinopsis : de forma predeterminada, todas las claves son necesarias cuando se crea una instancia definida TypedDict. total=Falseanula esta restricción y permite claves opcionales. Vea la siguiente demostración.

Dado

Un árbol de directorios de prueba:

ingrese la descripción de la imagen aquí

Código

Archivos en el directorio de prueba:

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

Manifestación

Si falta una clave, mypy se quejará en la línea de comando:

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

La configuración total=Falsepermite teclas opcionales:

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

Ver también

pylang
fuente