Tipos de Datos Estándar
Descubre cómo Pydantic maneja la conversión automática de tipos de datos nativos de Python. Se analizan enteros, cadenas, booleanos y listas, garantizando que la información ingresada sea la correcta.
Este capítulo examina cómo Pydantic aprovecha las anotaciones de tipo nativas de Python (type hints) para automatizar la validación y la coerción de datos. A lo largo de estas secciones, aprenderás el comportamiento del modo laxo frente a tipos primitivos como cadenas, enteros, flotantes y booleanos, así como la gestión avanzada de estructuras complejas: listas, tuplas, conjuntos y diccionarios tipados (TypedDict). Finalmente, dominarás el control de la ausencia de datos mediante tipos opcionales y la restricción estricta de valores mediante literales, garantizando la consistencia y robustez de tus modelos de datos.
3.1. Tipos primitivos en Python
Pydantic se basa en las anotaciones de tipo estándar de Python (type hints) para realizar una de sus funciones más potentes: la coerción de tipos (atribución o conversión automática de tipos). Cuando defines un campo en un modelo con un tipo primitivo, Pydantic no solo verifica que el dato de entrada sea de ese tipo, sino que intenta transformarlo de forma segura si es posible.
Por defecto, Pydantic opera en modo laxo (lax mode), lo que significa que prioriza la flexibilidad y la interpretación inteligente de los datos de entrada para ajustarlos al tipo primitivo declarado.
Los cuatro tipos primitivos principales que maneja Pydantic son:
str: Cadenas de texto.int: Números enteros.float: Números de punto flotante.bool: Valores booleanos (verdadero/falso).
Comportamiento de Coerción por Tipo
El siguiente flujo resume la estrategia que sigue Pydantic cuando recibe un dato para un tipo primitivo en modo laxo:
TEXT
1. Cadenas de texto (str)
Pydantic acepta strings de forma directa. Si recibe valores numéricos (int o float), los coercionará automáticamente a su representación en cadena de texto. Sin embargo, no aceptará estructuras complejas como diccionarios o listas.
2. Números enteros (int)
Acepta enteros directamente. Si se proporciona un float, Pydantic truncará la parte decimal (por ejemplo, 3.9 se convertirá en 3). Si recibe un str, intentará parsearlo como entero si la cadena contiene una representación numérica válida (por ejemplo, "42" se convierte en 42). Las cadenas con decimales (como "3.14") causarán un error de validación al intentar convertirse en entero.
3. Números de punto flotante (float)
Acepta enteros y flotantes. Las cadenas de texto que representen números (tanto enteros como decimales, por ejemplo "12.34" o "5") se convertirán automáticamente a float.
4. Valores booleanos (bool)
Es uno de los tipos más flexibles en modo laxo. Pydantic interpreta un amplio abanico de entradas para resolverlas como verdaderas o falsas:
- Valores verdaderos (
True):True, las cadenas"true","t","yes","y","on", y el entero1. - Valores falsos (
False):False, las cadenas"false","f","no","n","off", el entero0, y el flotante0.0.
(Nota: Las variaciones de mayúsculas y minúsculas en las cadenas mencionadas, como "True" o "YES", también son válidas).
Ejemplo Práctico de Coerción
A continuación, se muestra cómo un único modelo de Pydantic procesa entradas de distintos tipos mediante la conversión automática:
Python
Si ejecutas este código, la salida demostrará que todos los atributos se han transformado a sus tipos primitivos correctos sin lanzar ninguna excepción.
Casos de Falla Comunes
La coerción tiene límites lógicos para evitar la corrupción o pérdida ambigua de información. El siguiente fragmento expone escenarios donde Pydantic detiene la ejecución y lanza un ValidationError:
Python
Introducción al Modo Estricto (strict mode)
Aunque el comportamiento por defecto es laxo, Pydantic permite activar el modo estricto, ya sea a nivel de campo o a nivel global del modelo (esto último se detalla más adelante en el capítulo 12).
En modo estricto, Pydantic cancela la coerción de tipos y exige que el valor de entrada coincida de manera exacta con el tipo primitivo anotado. El único comportamiento permisible en modo estricto es que un campo de tipo float acepte un valor de tipo int (por ejemplo, pasar 10 a un campo float dará como resultado 10.0), ya que no existe riesgo de pérdida de precisión matemática. Cualquier otra conversión, como enviar "28" para un int, fallará de inmediato.
3.2. Listas, tuplas y conjuntos
Pydantic extiende su capacidad de validación y coerción hacia las estructuras de datos nativas de Python que actúan como contenedores de colecciones: listas (list), tuplas (tuple) y conjuntos (set o frozenset).
A partir de Python 3.9+, puedes tipar estas colecciones directamente utilizando los tipos integrados en minúsculas combinados con corchetes (por ejemplo, list[int]). Pydantic inspeccionará de forma recursiva cada elemento dentro del contenedor para asegurar que cumpla con el tipo primitivo o complejo especificado.
Comportamiento de Coerción de Contenedores
Al igual que ocurre con los tipos primitivos individuales, Pydantic opera por defecto en modo laxo para las colecciones. Esto implica un doble proceso de adaptación:
- Coerción de la estructura: Si pasas un tipo iterable que no coincide exactamente con el tipo de colección declarado, Pydantic intentará transformarlo al contenedor correcto. Por ejemplo, si un campo espera un
listy recibe unseto unatuple, lo convertirá automáticamente en una lista. - Coerción de los elementos: Una vez garantizado el contenedor, Pydantic iterará sobre cada elemento interno aplicando las reglas de conversión explicadas en la sección anterior (por ejemplo, transformando el string
"123"a un entero123si la definición eslist[int]).
TEXT
Tipado y Restricciones Específicas
1. Listas (list[...])
Representan secuencias mutables y ordenadas. Pydantic acepta cualquier iterable (excepto diccionarios y cadenas de texto directamente, para evitar la fragmentación accidental de caracteres) y genera una lista nativa de Python.
2. Conjuntos (set[...] y frozenset[...])
Representan colecciones de elementos únicos sin un orden específico. Si los datos de entrada contienen elementos duplicados, Pydantic los filtrará automáticamente para cumplir con las propiedades de un conjunto físico, reteniendo únicamente los valores únicos tras haber aplicado la coerción individual.
Nota sobre Mutabilidad: Recuerda que un
setes mutable, mientras que unfrozensetes inmutable. Pydantic preservará esta distinción devolviendo el objeto nativo correspondiente según tu anotación.
3. Tuplas (tuple[...])
Las tuplas admiten dos variantes de tipado muy distintas en Python, y Pydantic las procesa siguiendo reglas rigurosas para cada caso:
- Tuplas de tamaño variable (Homogéneas): Se definen usando la elipsis (
...). Por ejemplo,tuple[int, ...]le indica a Pydantic que la tupla puede recibir cualquier cantidad de elementos, pero todos deben poder convertirse a enteros. - Tuplas de tamaño fijo (Heterogéneas): Se definen enumerando explícitamente el tipo de cada posición. Por ejemplo,
tuple[int, str, bool]obliga a que la entrada tenga exactamente tres elementos y que el primero sea convertible a entero, el segundo a cadena y el tercero a booleano. Si la longitud no coincide, se arrojará un error de validación.
Ejemplo Práctico de Colecciones
El siguiente script ilustra cómo interactúa Pydantic con las distintas colecciones, sus conversiones automáticas y las validaciones de posición en las tuplas estructurales:
Python
Escenarios de Error Comunes
Las colecciones fallarán de forma inmediata si la estructura interna no se puede procesar o si el número de elementos de una tupla fija es incorrecto. El subproceso de validación detiene el ciclo y reporta exactamente el índice del elemento problemático:
Python
3.3. Diccionarios tipados
Pydantic ofrece un soporte nativo completo para validar estructuras basadas en diccionarios. En el ecosistema de Python, existen dos formas principales de abordar el tipado de mapas clave-valor: el tipo genérico estándar dict[K, V] y la clase especializada TypedDict (introducida en typing).
Mientras que dict[K, V] define un diccionario homogéneo donde todas las llaves tienen el mismo tipo y todos los valores comparten la misma naturaleza, TypedDict te permite estructurar diccionarios heterogéneos con llaves fijas y tipos específicos para cada una de ellas, actuando como un paso intermedio entre un diccionario convencional y un modelo completo de Pydantic.
Validando Diccionarios Estándar (dict[K, V])
Cuando declaras un campo utilizando dict[Clave, Valor], Pydantic valida de forma independiente tanto las claves como los valores del mapa. Si el origen es un objeto JSON (donde las llaves son obligatoriamente cadenas de texto), Pydantic aplicará las reglas de coerción correspondientes sobre la clave para convertirla al tipo nativo deseado (por ejemplo, de "101" a 101 si se define dict[int, str]).
Python
Integración con TypedDict
A diferencia de dict[K, V], un TypedDict restringe qué llaves exactas pueden existir y qué tipo de dato debe albergar cada una. Pydantic respeta esta firma, permitiéndote anidar diccionarios tipados dentro de tus modelos sin necesidad de transformar cada objeto intermedio en un BaseModel independiente.
Esto resulta muy útil cuando trabajas con código heredado (legacy) o APIs que devuelven estructuras JSON fijas y no deseas poblar tu arquitectura con excesivas clases de Pydantic.
TEXT
Reglas de obligatoriedad en TypedDict
Por defecto en Python, todas las llaves definidas en un TypedDict son obligatorias a menos que se configure el parámetro total=False en la declaración de la clase, o se utilice el modificador NotRequired (disponible en typing o typing_extensions). Pydantic obedece de forma estricta esta especificación durante el proceso de análisis y parsing.
Ejemplo Práctico con TypedDict
El siguiente ejemplo demuestra cómo declarar un TypedDict, incorporarle restricciones de opcionalidad mediante NotRequired, y utilizarlo como anotación de tipo dentro de un modelo principal de Pydantic:
Python
Comportamiento frente a Llaves Extrañas
Si un diccionario de entrada incluye llaves adicionales que no están presentes en la definición del TypedDict, Pydantic adoptará un comportamiento conservador por defecto: preservará e incluirá las llaves extra en el diccionario final sin validarlas.
Este comportamiento difiere de cómo gestiona Pydantic los campos adicionales directamente introducidos en un BaseModel (donde las propiedades extra suelen descartarse de manera silenciosa por defecto). Si necesitas alterar esta directiva para rechazar o eliminar datos excedentes en diccionarios, requerirás la configuración explícita del modelo a través de ModelConfig, aspecto que se detalla exhaustivamente en la tercera parte de esta documentación.
3.4. Tipos Opcionales (Optional)
En el desarrollo de software, es sumamente común que ciertos datos sean desconocidos, no apliquen o simplemente no se proporcionen. En Python, la ausencia de un valor se representa mediante el objeto None. Para declarar que un campo puede aceptar un tipo específico o, en su defecto, el valor None, Pydantic se apoya en los estándares de tipado del lenguaje.
A partir de Python 3.10+, la forma nativa y recomendada de declarar un tipo opcional es utilizando el operador de unión | (por ejemplo, str | None). En versiones anteriores, se utiliza el modificador Optional[...] importado del módulo typing (por ejemplo, Optional[str]). Ambas sintaxis son idénticas ante los ojos de Pydantic.
La Distinción Crítica: Opcional vs. Valor Predeterminado
Existe una confusión muy frecuente al empezar a utilizar Pydantic: asumir que declarar un campo como Optional lo convierte automáticamente en un campo no obligatorio al inicializar el modelo. Esto es falso.
- Anotación de Tipo (
str | None): Define qué clase de datos se permiten dentro del campo una vez se crea el modelo. Le indica a Pydantic: "Si me pasas un dato, puede ser un string o puede ser None". - Valor por Defecto (
= None): Define si el campo es requerido o no en el momento de la construcción. Le indica a Pydantic: "Si no te pasan este parámetro, inicialízalo con este valor".
El siguiente diagrama ilustra la matriz de comportamiento resultante de combinar ambas propiedades:
TEXT
Ejemplo Práctico de Configuraciones Opcionales
El siguiente modelo de Pydantic demuestra de manera práctica los cuatro comportamientos de la matriz anterior, forzando los errores de validación para entender los límites de cada definición:
Python
Comportamiento de Coerción con Tipos de Unión
Cuando utilizas una unión que incluye un tipo primitivo y None (como int | None), Pydantic aplica las reglas de la siguiente manera:
- Si el valor de entrada es exactamente
None, se asigna de inmediato sin alterar nada. - Si el valor es cualquier otra cosa (por ejemplo, el string
"100"), Pydantic intentará realizar la coerción hacia el tipo primitivo indicado (transformándolo en el entero100). - Solo si la coerción hacia el tipo primitivo falla por completo (por ejemplo, enviando
"hola"a unint | None), se disparará unValidationError. El valor no se degradará aNonede forma automática solo porque la conversión falló; Pydantic prefiere la seguridad y te notificará que el dato original no era válido.
3.5. Tipos literales (Literal)
El tipo Literal (importado del módulo estándar typing) te permite restringir el valor de un campo a una serie de opciones exactas y predefinidas. A diferencia de un tipo primitivo como str, que acepta cualquier cadena de texto, un campo anotado como Literal["Lectura", "Escritura"] solo aceptará de forma válida una de esas dos palabras exactas.
En el ecosistema de Pydantic, Literal es una herramienta fundamental para validar esquemas de datos rígidos, configurar enumeraciones rápidas sin necesidad de recurrir a la estructura formal de un Enum de Python, y actuar como el mecanismo clave para el despacho discriminado de modelos (identificar automáticamente qué submodelo usar basándose en el valor de una llave).
Coerción y Rigidez en Tipos Literales
A diferencia del comportamiento altamente flexible que Pydantic muestra con los tipos primitivos (como transformar "yes" en True), con los tipos Literal se aplica una política de validación mucho más estricta, incluso operando en el modo laxo por defecto.
- Sensibilidad a mayúsculas y minúsculas: Las cadenas de texto se evalúan de forma exacta. Si defines
Literal["pendiente"], la entrada"Pendiente"o"PENDIENTE"fallará la validación. - Coerción inteligente limitada: Pydantic no realizará transformaciones que alteren la naturaleza semántica del literal. Sin embargo, si el valor esperado es un número o un booleano (por ejemplo,
Literal[1, 2]), e ingresas una cadena numéricamente equivalente como"1", Pydantic aplicará la coerción básica del tipo primitivo antes de evaluar la coincidencia con las opciones del literal.
TEXT
Ejemplo Práctico de Tipos Literales
El siguiente script ejemplifica cómo configurar opciones obligatorias mediante Literal, la rigidez de su validación ante variaciones de texto y el comportamiento de la coerción numérica:
Python
Resumen del Capítulo
En este Capítulo 3: Tipos de Datos Estándar, hemos explorado en profundidad la capacidad intrínseca de Pydantic para interpretar, transformar y validar la información entrante utilizando las anotaciones de tipo estándar de Python.
- Tipos Primitivos: Analizamos cómo funciona el modo laxo corporativo de Pydantic, aplicando reglas de coerción automática y segura sobre cadenas (
str), enteros (int), flotantes (float) y booleanos (bool), estableciendo los límites lógicos para evitar la corrupción de datos. - Colecciones: Estudiamos la validación recursiva en contenedores homogéneos y heterogéneos utilizando listas, tuplas y conjuntos, destacando el comportamiento estricto de posicionamiento y tamaño en las tuplas fijas.
- Diccionarios Tipados: Evaluamos el soporte para mapas clave-valor tradicionales mediante
dict[K, V]y la compatibilidad avanzada con estructurasTypedDict, facilitando el modelado de datos sin necesidad de instanciar múltiples submodelos. - Tipos Opcionales: Desmitificamos la confusión común entre la opcionalidad de tipo (
str | None) y la obligatoriedad de presencia en la inicialización, comprendiendo el impacto de los valores predeterminados. - Tipos Literales: Concluimos con el uso de
Literalpara restringir campos a conjuntos cerrados de valores exactos, sentando las bases para validaciones estrictas y flujos de control basados en etiquetas de datos fijas.
© 2026 Esdocu. Contenido bajo licencia MIT.
Editar esta página