Às vezes você precisa de um objeto simples para agrupar valores por atributos, sem criar uma classe completa. types.SimpleNamespace oferece exatamente isso: um contêiner mutável baseado em __dict__, com construção por argumentos nomeados, representação legível e igualdade baseada nos atributos armazenados.
Neste guia, você aprenderá a criar namespaces, converter dicionários, adicionar e remover atributos, comparar instâncias, copiar objetos, trabalhar com dados aninhados, integrar com JSON e argparse e decidir quando preferir dataclass, TypedDict, NamedTuple ou uma classe real.
Primeiro SimpleNamespace
from types import SimpleNamespace
usuario = SimpleNamespace(nome="Ana", ativo=True)
print(usuario.nome)
print(usuario.ativo)
Os argumentos nomeados são inseridos no __dict__ da instância. Não há declaração prévia de campos, validação nem conversão automática.
Adicionar atributos depois
usuario.id = 42
usuario.email = "ana@example.com"
O objeto é dinâmico e mutável. Isso é conveniente para protótipos e dados temporários, mas nomes digitados incorretamente podem criar atributos novos silenciosamente.
Construir a partir de dict
dados = {"host": "localhost", "porta": 8000}
config = SimpleNamespace(**dados)
print(config.porta)
As chaves precisam ser strings válidas como argumentos nomeados. Chaves com hífen, espaços ou nomes não textuais não podem ser expandidas diretamente com **.
Voltar para dicionário
como_dict = vars(config)
vars(config) devolve o dicionário real de atributos, não uma cópia. Alterá-lo modifica a instância.
snapshot = vars(config).copy()
Use cópia quando precisar de um estado independente.
Representação legível
print(SimpleNamespace(x=1, y=2))
# namespace(x=1, y=2)
O repr é útil em logs e testes, mas pode incluir valores sensíveis. Não imprima namespaces com tokens, senhas ou dados pessoais sem redaction.
Igualdade
a = SimpleNamespace(x=1, y=2)
b = SimpleNamespace(y=2, x=1)
print(a == b) # True
A igualdade compara os dicionários de atributos. A ordem de inserção não importa. Comparações com outros tipos normalmente não representam o mesmo contrato.
Objetos não hashable
Como é mutável e define igualdade por conteúdo, SimpleNamespace não deve ser usado como chave de dicionário ou membro de set. Para valores imutáveis e hashable, considere uma dataclass frozen ou NamedTuple.
Remover atributos
del usuario.email
Depois da exclusão, acessar o atributo gera AttributeError. Use hasattr() ou getattr(objeto, nome, padrão) quando o campo for opcional.
getattr e setattr
nome_campo = "timeout"
setattr(config, nome_campo, 30)
valor = getattr(config, nome_campo)
Essas funções são úteis quando nomes vêm de metadados. Valide uma allowlist antes de aceitar nomes externos, especialmente quando outros atributos do objeto poderiam ser sobrescritos.
Dados aninhados
app = SimpleNamespace(
banco=SimpleNamespace(host="db", porta=5432),
debug=False,
)
Dicionários aninhados não viram namespaces automaticamente. Crie a estrutura recursivamente quando a notação por ponto for desejada.
Conversão recursiva
def para_namespace(valor):
if isinstance(valor, dict):
return SimpleNamespace(
**{chave: para_namespace(item) for chave, item in valor.items()}
)
if isinstance(valor, list):
return [para_namespace(item) for item in valor]
return valor
Antes de usar esse helper com dados externos, confirme que todas as chaves são identificadores adequados e que não conflitam com nomes especiais.
Serialização JSON
O encoder padrão não serializa SimpleNamespace diretamente. Converta com uma função default:
import json
texto = json.dumps(config, default=vars)
Em estruturas aninhadas, default=vars pode funcionar para objetos com __dict__, mas também pode expor mais campos do que o esperado. Uma conversão explícita é mais segura em APIs públicas.
Cópia rasa
from copy import copy
copia = copy(app)
A cópia rasa cria outro namespace, mas valores mutáveis aninhados continuam compartilhados. Use deepcopy() apenas quando a estrutura suportar cópia profunda e o custo for aceitável.
Argparse
argparse.ArgumentParser.parse_args() retorna um objeto semelhante a namespace e pode receber uma instância existente:
from argparse import ArgumentParser
from types import SimpleNamespace
parser = ArgumentParser()
parser.add_argument("--porta", type=int, default=8000)
config = parser.parse_args(namespace=SimpleNamespace())
Para configurações maiores, valide e converta o resultado para um modelo explícito antes de iniciar a aplicação.
Prototipagem
SimpleNamespace é excelente para testes rápidos, stubs, fixtures e retorno interno de funções quando uma classe formal seria excesso. Ele torna resultado.valor mais legível que índices de tupla.
Não é um schema
O objeto não declara campos obrigatórios, tipos, defaults ou documentação. Ferramentas estáticas veem atributos dinâmicos com pouca precisão. Para contratos duradouros, uma dataclass ou TypedDict é mais clara.
SimpleNamespace versus dataclass
from dataclasses import dataclass
@dataclass
class Config:
host: str
porta: int = 8000
Dataclasses oferecem campos explícitos, type hints, construtor previsível, opções de imutabilidade e integração melhor com IDEs. Use SimpleNamespace quando a estrutura é temporária ou genuinamente dinâmica.
Versus TypedDict
TypedDict descreve dicionários acessados por chaves e existe principalmente para análise estática. SimpleNamespace fornece acesso por atributos em runtime. Escolha de acordo com o formato real da API.
Versus NamedTuple
NamedTuple é uma tupla imutável, indexável e hashable, com campos fixos. SimpleNamespace é mutável, não indexável e aceita atributos novos. Para registros estáveis e leves, NamedTuple pode ser melhor.
Versus uma classe comum
Uma classe permite invariantes, propriedades, métodos, validação e encapsulamento. Quando o objeto ganha comportamento ou participa de uma API pública, migre para uma classe explícita.
Valores padrão
SimpleNamespace não possui declaração de defaults. Crie uma função construtora:
def nova_config(**overrides):
valores = {"host": "localhost", "porta": 8000, "debug": False}
valores.update(overrides)
return SimpleNamespace(**valores)
Valide chaves desconhecidas para evitar erros de digitação.
Campos calculados
Você pode atribuir um valor calculado, mas ele não se atualiza automaticamente quando dependências mudam. Para propriedades derivadas, use uma classe com @property.
Herança
É possível subclassificar SimpleNamespace, mas, se você precisa de métodos, validação e estrutura fixa, uma classe normal ou dataclass costuma comunicar melhor a intenção.
Segurança com dados externos
Não transforme JSON arbitrário em atributos e depois use esses atributos para controlar importações, caminhos ou chamadas sem validação. A notação por ponto não torna o conteúdo confiável.
Erros comuns
- Tratar como modelo validado: qualquer atributo pode ser criado.
- Usar vars como cópia: ele devolve o dicionário real.
- Esperar conversão recursiva: dicionários internos permanecem dict.
- Usar em API pública estável: campos não estão declarados.
- Logar segredos: o repr mostra os atributos.
- Compartilhar cópia rasa: objetos internos continuam os mesmos.
Exemplo completo: resultado de processamento
from types import SimpleNamespace
def processar(linhas):
erros = []
validas = []
for numero, linha in enumerate(linhas, 1):
try:
validas.append(normalizar(linha))
except ValueError as erro:
erros.append((numero, str(erro)))
return SimpleNamespace(
total=len(linhas),
validas=validas,
erros=erros,
sucesso=not erros,
)
resultado = processar(linhas)
if resultado.sucesso:
salvar(resultado.validas)
O namespace funciona bem como retorno interno simples. Se esse resultado se tornar parte de uma biblioteca pública, uma dataclass tipada oferece contrato melhor.
Conclusão
types.SimpleNamespace é um contêiner leve para valores acessados por atributos. Ele reduz boilerplate em protótipos, testes e estruturas temporárias, mantendo representação e igualdade convenientes.
A documentação oficial de SimpleNamespace descreve a classe. Use-a para dados dinâmicos simples e migre para dataclass, TypedDict ou classe comum quando precisar de schema, validação ou comportamento.







