TypedDict & NamedTuple
TypedDict añade forma estática a los dicts, perfecto para blobs JSON. NamedTuple proporciona registros inmutables más ligeros que dataclasses para filas de solo lectura.
Receta
from typing import TypedDict
class UserRow(TypedDict):
id: int
email: str
def load(row: UserRow) -> str:
return row["email"]Cuándo usar esto:
- Para tipar estructuras de
response.json() - Filas de pipeline CSV/JSON como dicts
- Registros ligeros inmutables a partir de tuplas
- Tipado gradual sin cambiar los tipos en tiempo de ejecución
Ejemplo de Trabajo
from typing import NamedTuple, NotRequired, TypedDict
class Address(TypedDict, total=False):
street: str
city: str
zip: NotRequired[str]
class User(TypedDict):
id: int
name: str
address: Address
class Point(NamedTuple):
x: int
y: int
def format_user(user: User) -> str:
city = user.get("address", {}).get("city", "unknown")
return f"{user['name']} ({city})"
def distance(a: Point, b: Point) -> float:
return ((a.x - b.x) ** 2 + (a.y - b.y) ** 2) ** 0.5
if __name__ == "__main__":
row: User = {"id": 1, "name": "Ada", "address": {"city": "London"}}
print(format_user(row))
print(distance(Point(0, 0), Point(3, 4)))Lo que esto demuestra:
total=Falsehace que las claves de Address sean opcionales estáticamenteNotRequiredmarca claves opcionales en un TypedDict que de otro modo sería total (3.11+)- TypedDict sigue siendo un dict en tiempo de ejecución - acceso
user["name"] - Campos de NamedTuple accedidos como atributos con desempaquetado de tuplas
Inmersión Profunda
Cómo Funciona
- TypedDict - Constructo puramente de tipado; sin validación en tiempo de ejecución por defecto.
- flag
total- Todas las claves son requeridas cuandototal=True(por defecto). - Herencia - TypedDict puede extender otros TypedDicts para formas de API anidadas.
- NamedTuple - Subclase de tupla; inmutable; puede tener métodos de forma esporádica.
- typing_extensions - Backports para Python antiguo; 3.14 tiene NotRequired en typing.
Elige el Tipo de Registro
| Tipo | Tiempo de Ejecución | Mutable |
|---|---|---|
| TypedDict | dict | Sí |
| NamedTuple | tuple | No |
| dataclass | object | Configurable |
| Pydantic | BaseModel | Sí |
Notas de Python
# Clave requerida en TypedDict parcial (3.11+)
class Config(TypedDict, total=False):
debug: NotRequired[bool]
host: str # requerido si se usa Required[] en patrones parcialesTrampas Comunes
- TypedDict sin validación en tiempo de ejecución - Los tipos incorrectos pasan hasta que se usan. Solución: Pydantic en los límites.
- Se permiten claves extra - TypedDict no prohíbe claves desconocidas a menos que sea un TypedDict cerrado (las características de PEP 728+ varían). Solución: Validar externamente.
- Campos mutables en NamedTuple si no se tiene cuidado - Los campos son inmutables pero los campos de objeto podrían contener mutables. Solución: Tupla de inmutables.
- TypedDict vs JSON de dataclass - TypedDict permanece como dict para APIs que esperan Mapping. Solución: Elegir según el consumidor.
- Errores tipográficos en claves - mypy detecta
user["emial"]; el tiempo de ejecución todavía produce KeyError. Solución: Verificación estática + pruebas.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Pydantic BaseModel | Validación HTTP | Acceso a dict en bucle caliente |
| dataclass | Métodos + valores por defecto | Debe permanecer como dict |
| attrs | Ecosistema attrs | Mínimo de la librería estándar |
| dict[str, Any] simple | Solo prototipo | API de producción |
Preguntas Frecuentes
¿TypedDict o dataclass?
TypedDict cuando el valor debe permanecer como dict (APIs JSON). dataclass para objetos de dominio con comportamiento.
¿NamedTuple o dataclass frozen?
NamedTuple para semántica de tupla más ligera; dataclass frozen cuando se necesitan valores por defecto y métodos.
¿claves opcionales en TypedDict?
total=False en todo el dict o NotRequired por clave en 3.11+.
¿TypedDict anidado?
Componer TypedDicts más pequeños como tipos de campo - refleja el anidamiento JSON.
¿convertir TypedDict a dataclass?
Mapeo manual o Pydantic model_validate en capas de conexión.
¿tipar campos de NamedTuple?
Anotar en el cuerpo de la clase - NamedTuple soporta anotaciones PEP 526.
¿TypedDict isinstance?
No es un tipo en tiempo de ejecución - isinstance solo comprueba dict. Usa una librería de validación.
¿tipar csv DictReader?
Convertir filas a TypedDict después de validar que las claves requeridas están presentes.
¿herencia de total=False?
El hijo puede añadir claves opcionales; entender las reglas de claves requeridas a través de la herencia.
¿modelo de respuesta de FastAPI?
Pydantic preferido para OpenAPI; TypedDict para contratos de dict de servicios internos.
Relacionado
- Genéricos Integrados y de Colección - dict[str, T]
- dataclasses - registros mutables
- Optional, Union & el Operador | - campos opcionales
- Literal, Final & Annotated - valores de dict restringidos
Versiones de Stack: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.