Opcional, Unión y el Operador |
Las uniones expresan valores que pueden tomar múltiples tipos. La sintaxis X | Y (3.10+) reemplaza Union[X, Y]; los tipos anulables son uniones con None.
Receta
def parse_count(raw: str | None) -> int:
if raw is None:
return 0
return int(raw)
def format_id(value: int | str) -> str:
return str(value)Cuándo usar esto:
- Al analizar variables de configuración y entorno opcionales
- Funciones que devuelven "valor o ausente"
- Al aceptar múltiples representaciones de entrada
- Al modelar éxito/fracaso sin excepciones
Ejemplo Funcional
from dataclasses import dataclass
@dataclass
class User:
id: int
email: str | None
def email_domain(user: User) -> str | None:
if user.email is None:
return None
return user.email.split("@", 1)[1]
def describe(value: int | str | None) -> str:
match value:
case None:
return "ausente"
case int(n):
return f"número {n}"
case str(s):
return f"texto {s}"
def coalesce(*values: str | None) -> str:
for v in values:
if v is not None:
return v
return ""
if __name__ == "__main__":
print(describe(42))
print(email_domain(User(1, None)))Lo que esto demuestra:
is None/is not Nonereduce los tipos opcionales para los verificadoresmatch/casecon patrones tipados refina las unionesstr | Noneen argumentos variádicos para cadenas de respaldo- Devolver
Noneexplícitamente en el tipo de retorno
Inmersión Profunda
Cómo Funciona
- Unión - El valor puede ser cualquier tipo miembro; el verificador requiere manejar todos los casos.
- Reducción de tipos (Narrowing) - Los refinamientos del flujo de control reducen la unión a un miembro específico.
- Alias Opcional -
Optional[T]significaT | None- todavía válido,|es el estilo preferido. - Exhaustividad -
mypy --strictadvierte sobre miembros de unión no manejados enmatch. - TypeGuard - Funciones que reducen tipos para los llamadores (avanzado).
Herramientas de Reducción de Tipos
| Herramienta | Ejemplo |
|---|---|
is None | Opcional -> T |
isinstance | Miembros de unión |
match/case | Estructural + tipos |
assert | Pista solo para el verificador |
Notas de Python
from typing import TypeGuard
def is_str_list(val: list[object]) -> TypeGuard[list[str]]:
return all(isinstance(x, str) for x in val)Trampas Comunes
- Comprobación de verdad vs None -
if email:trata la cadena vacía como ausente de manera diferente ais None. Solución: Elegir explícitamente la semántica deNoneo de valor "falsy". - Uso excesivo de Optional - Todo
T | Noneoscurece los campos requeridos. Solución: Separar campos de modelo requeridos y opcionales. - Orden de la unión - Generalmente irrelevante; los verificadores los tratan simétricamente.
- Devolver
Anydesde una rama de unión - Amplía el resultado. Solución: Tipo de retorno consistente por rama. nullde JSON - Se mapea aNoneen Python - validar en el límite con Pydantic.
Alternativas
| Alternativa | Usar Cuándo | No Usar Cuándo |
|---|---|---|
Tipos Result/Either | Canal de error explícito | Cuando las excepciones son idiomáticas |
Literal | Conjunto fijo de valores | Tipos de alcance abierto |
| Excepciones | Ausencia verdaderamente excepcional | Campo opcional esperado |
| Objeto centinela | Distinguir ausencia de None | Cuando Optional simple es suficiente |
Preguntas Frecuentes
¿Optional o `|` None?
Mismo significado - prefiere str | None en bases de código modernas de Python 3.10+.
¿Cómo reducir una unión?
isinstance, match, igualdad a None, o funciones TypeGuard.
¿Unión en `isinstance`?
isinstance(x, (int, str)) es válido en tiempo de ejecución; el verificador reduce en consecuencia.
¿Campo opcional en `dataclass`?
field: str | None = None o Optional con valor predeterminado None.
¿PEP 604 `|` con `None`?
int | None reemplaza Optional[int] - lectura más clara.
¿`match` exhaustivo?
Incluir case _: o mypy puede advertir sobre uniones no manejadas bajo configuraciones estrictas.
¿Unión de modelos?
User | Admin con un Protocol compartido o una clase base para campos comunes.
¿`None` en API JSON?
Los campos opcionales de Pydantic mapean null; documentar nullable de OpenAPI cuidadosamente.
¿`assert` para el verificador?
assert x is not None reduce para mypy - operación nula en tiempo de ejecución si la optimización elimina los asserts (-O).
¿Demasiadas uniones?
Refactorizar a una clase base, Protocol, o una unión discriminada con un campo de etiqueta literal.
Relacionado
- Fundamentos de las Pistas de Tipo - fundamentos
- Literal, Final y Annotated - uniones precisas
- TypedDict y NamedTuple - claves opcionales
- Flujo de Control - reducción con
match
Versiones de la Pila: 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+.