A veces necesitas un objeto sencillo para agrupar valores mediante atributos sin definir una clase completa. types.SimpleNamespace ofrece exactamente eso: un contenedor mutable basado en __dict__, construido con argumentos nombrados, con representación legible e igualdad basada en los atributos almacenados.
Esta guía explica cómo crear namespaces, convertir diccionarios, añadir y eliminar atributos, comparar instancias, copiar objetos, manejar datos anidados, integrar JSON y argparse y decidir cuándo conviene una dataclass, TypedDict, NamedTuple o clase normal.
Primer SimpleNamespace
from types import SimpleNamespace
usuario = SimpleNamespace(nombre="Ana", activo=True)
print(usuario.nombre)
print(usuario.activo)
Los argumentos nombrados se insertan en el __dict__ de la instancia. No existe declaración previa de campos, validación de runtime ni conversión automática.
Añadir atributos después
usuario.id = 42
usuario.email = "ana@example.com"
El objeto es dinámico y mutable. Esto resulta práctico para prototipos y estado temporal, pero un nombre escrito incorrectamente puede crear un nuevo atributo en silencio.
Construir desde un diccionario
datos = {"host": "localhost", "puerto": 8000}
config = SimpleNamespace(**datos)
print(config.puerto)
Las claves deben ser strings aceptadas como nombres de argumentos. Claves con guiones, espacios o valores no textuales no pueden expandirse directamente con **.
Volver a diccionario
mapping = vars(config)
vars(config) devuelve el diccionario real de atributos, no una copia. Modificarlo cambia el namespace.
snapshot = vars(config).copy()
Crea una copia cuando necesites estado independiente.
Representación legible
print(SimpleNamespace(x=1, y=2))
# namespace(x=1, y=2)
La representación ayuda en pruebas y depuración, pero puede mostrar datos sensibles. Elimina contraseñas, tokens y datos personales antes de registrar el objeto.
Igualdad
a = SimpleNamespace(x=1, y=2)
b = SimpleNamespace(y=2, x=1)
print(a == b) # True
La igualdad compara los diccionarios de atributos. El orden de inserción no importa. Como la clase es mutable, no está pensada como clave hashable ni miembro de set.
Eliminar atributos
del usuario.email
Acceder al atributo eliminado genera AttributeError. Usa hasattr() o getattr(objeto, nombre, predeterminado) para campos opcionales.
getattr y setattr dinámicos
nombre_campo = "timeout"
setattr(config, nombre_campo, 30)
valor = getattr(config, nombre_campo)
Estas funciones son útiles cuando los nombres proceden de metadatos. Valida una allowlist antes de aceptar nombres externos, especialmente si podrían sobrescribir atributos especiales.
Namespaces anidados
app = SimpleNamespace(
base_datos=SimpleNamespace(host="db", puerto=5432),
debug=False,
)
Los diccionarios internos no se convierten automáticamente. Construye la estructura explícitamente cuando quieras notación por punto.
Conversión recursiva
def a_namespace(valor):
if isinstance(valor, dict):
return SimpleNamespace(
**{clave: a_namespace(item) for clave, item in valor.items()}
)
if isinstance(valor, list):
return [a_namespace(item) for item in valor]
return valor
Antes de usar este helper con datos externos, verifica que todas las claves sean identificadores adecuados y que no se acepten nombres especiales inesperados.
Serialización JSON
El encoder JSON estándar no serializa SimpleNamespace directamente:
import json
texto = json.dumps(config, default=vars)
default=vars también puede exponer atributos de otros objetos con __dict__. La conversión explícita es más segura en APIs públicas.
Copias
from copy import copy
copia = copy(app)
Una copia superficial crea otro namespace, pero los valores mutables internos continúan compartidos. Usa deepcopy() solo cuando la estructura lo soporte y el coste esté justificado.
Integración con argparse
ArgumentParser.parse_args() devuelve un objeto similar y puede rellenar una instancia existente:
from argparse import ArgumentParser
from types import SimpleNamespace
parser = ArgumentParser()
parser.add_argument("--puerto", type=int, default=8000)
config = parser.parse_args(namespace=SimpleNamespace())
En aplicaciones grandes, valida y convierte el resultado a un modelo explícito antes de iniciar servicios.
Prototipos y fixtures
SimpleNamespace es útil para pruebas rápidas, stubs, fixtures y valores de retorno internos cuando una clase formal añade demasiado código. resultado.valor puede ser más legible que índices de tupla.
No es un schema
El objeto no declara campos obligatorios, tipos, defaults ni documentación. Los analizadores estáticos tienen poca información sobre atributos dinámicos. Una dataclass o TypedDict ofrece un contrato más fuerte.
SimpleNamespace frente a dataclass
from dataclasses import dataclass
@dataclass
class Config:
host: str
puerto: int = 8000
Dataclass ofrece campos explícitos, type hints, construcción predecible, opciones de inmutabilidad y mejor soporte de IDE. Usa SimpleNamespace cuando la forma sea temporal o realmente dinámica.
Frente a TypedDict
TypedDict describe diccionarios accedidos por claves y sirve principalmente al análisis estático. SimpleNamespace proporciona acceso por atributos en runtime. Elige según el formato real de los datos.
Frente a NamedTuple
NamedTuple es inmutable, indexable, hashable y posee campos fijos. SimpleNamespace es mutable, no está orientado a índices y acepta atributos nuevos. Para registros estables y ligeros, NamedTuple puede ser mejor.
Frente a una clase normal
Una clase permite invariantes, propiedades, métodos, validación y encapsulación. Cuando el objeto gana comportamiento o forma parte de una API pública, migra a una clase explícita.
Proporcionar defaults
def nueva_config(**overrides):
valores = {"host": "localhost", "puerto": 8000, "debug": False}
desconocidas = set(overrides) - set(valores)
if desconocidas:
raise TypeError(f"opciones desconocidas: {sorted(desconocidas)}")
valores.update(overrides)
return SimpleNamespace(**valores)
Comprobar nombres desconocidos evita errores tipográficos silenciosos.
Campos calculados
Puedes guardar un valor calculado, pero no se actualizará cuando cambien sus dependencias. Usa una propiedad en una clase si el valor debe derivarse siempre del estado actual.
Herencia
SimpleNamespace puede heredarse, pero si necesitas métodos, validación y estructura fija, una clase normal o dataclass suele comunicar mejor la intención.
Seguridad con datos externos
No conviertas JSON arbitrario a atributos para después controlar imports, rutas, queries o llamadas sin validación. La notación por punto no vuelve confiable la entrada.
Concurrencia
El namespace no sincroniza accesos. Varias threads modificando atributos requieren la misma disciplina de locks que un diccionario compartido. Para configuración leída por muchos workers, prefiere snapshots inmutables.
Errores comunes
- Tratarlo como modelo validado: cualquier atributo puede crearse.
- Usar vars como mapping independiente: devuelve el diccionario vivo.
- Esperar conversión recursiva: los dict internos siguen siendo dict.
- Publicarlo como contrato estable: los campos no están declarados.
- Registrar secretos: el repr muestra atributos.
- Suponer que una copia superficial aísla: los objetos internos siguen compartidos.
Ejemplo completo: resultado de procesamiento
from types import SimpleNamespace
def procesar(lineas):
errores = []
validas = []
for numero, linea in enumerate(lineas, 1):
try:
validas.append(normalizar(linea))
except ValueError as error:
errores.append((numero, str(error)))
return SimpleNamespace(
total=len(lineas),
validas=validas,
errores=errores,
exito=not errores,
)
resultado = procesar(lineas)
if resultado.exito:
guardar(resultado.validas)
El namespace funciona como retorno interno sencillo. Si el resultado se convierte en parte de una biblioteca pública, una dataclass tipada ofrece un contrato más claro.
Conclusión
types.SimpleNamespace es un contenedor ligero para valores accedidos mediante atributos. Reduce boilerplate en prototipos, pruebas y estructuras temporales, con representación e igualdad útiles.
La documentación oficial de SimpleNamespace define la clase. Úsala para datos dinámicos simples y migra a dataclass, TypedDict, NamedTuple o clase normal cuando necesites schema, validación o comportamiento.







