Dicionários Aninhados
Aprenda a criar, acessar, modificar, excluir e iterar dicionários aninhados em Python com exemplos claros e boas práticas.
Um dicionário aninhado é um dicionário que contém outros dicionários como valores. Isso cria uma estrutura de dados hierárquica (em forma de árvore) ideal para representar dados agrupados do mundo real — como uma coleção de perfis de usuários, um arquivo de configuração ou uma resposta de API JSON.
Este capítulo abrange:
- Criação de dicionários aninhados
- Acesso a valores em qualquer profundidade
- Modificação e adição de entradas
- Exclusão de chaves e sub-dicionários
- Iteração sobre dicionários aninhados
- Uso de
.get()para evitarKeyError - Trabalho com dados profundamente aninhados e JSON
Criando Dicionários Aninhados
Defina um dicionário cujos valores são eles próprios dicionários:
people = {
"person1": {"name": "Alice", "age": 30},
"person2": {"name": "Bob", "age": 25},
}
print(people)
# {'person1': {'name': 'Alice', 'age': 30}, 'person2': {'name': 'Bob', 'age': 25}}Você também pode construir um dicionário aninhado de forma incremental:
people = {}
people["person1"] = {"name": "Alice", "age": 30}
people["person2"] = {"name": "Bob", "age": 25}
print(people["person1"]) # {'name': 'Alice', 'age': 30}Não há limite de profundidade — um valor interno pode, ele mesmo, ser um dicionário aninhado.
Acessando Valores de Dicionários Aninhados
Encadeie colchetes para acessar qualquer nível:
Acesso Seguro com .get()
Acessos encadeados com colchetes lançam um KeyError se uma chave estiver ausente. Use .get() para retornar um valor padrão em vez disso:
people = {
"person1": {"name": "Alice", "age": 30},
}
# Safe: returns None if "person3" does not exist
print(people.get("person3", {}).get("name", "Unknown")) # Unknown
# Risky: raises KeyError
# print(people["person3"]["name"])O padrão .get(outer_key, {}).get(inner_key, default) é a forma idiomática de ler dados aninhados opcionais sem um bloco try/except.
Modificando Valores de Dicionários Aninhados
Atribua diretamente por meio da cadeia de chaves:
Adicionando Novos Sub-Dicionários
Atribua um novo dicionário literal a uma nova chave externa:
Usando setdefault() para Adicionar Apenas Quando Ausente
setdefault() insere uma chave com um valor padrão somente se ela ainda não existir — útil ao construir dicionários aninhados a partir de um fluxo de dados:
scores = {}
for student, subject, grade in [
("Alice", "math", 90),
("Alice", "english", 85),
("Bob", "math", 78),
]:
scores.setdefault(student, {})[subject] = grade
print(scores)
# {'Alice': {'math': 90, 'english': 85}, 'Bob': {'math': 78}}Excluindo Chaves e Sub-Dicionários
Use del para remover uma chave (e seu valor) em qualquer nível:
people = {
"person1": {"name": "Alice", "age": 30},
"person2": {"name": "Bob", "age": 25},
"person3": {"name": "Carol", "age": 40},
}
del people["person2"]["age"] # remove one key from an inner dict
del people["person3"] # remove an entire sub-dictionary
print(people)
# {'person1': {'name': 'Alice', 'age': 30}, 'person2': {'name': 'Bob'}}Use .pop() se você também precisar do valor excluído:
removed = people["person1"].pop("age", None)
print(removed) # 30
print(people["person1"]) # {'name': 'Alice'}Iterando sobre Dicionários Aninhados
Percorrer chaves externas e itens internos
people = {
"person1": {"name": "Alice", "age": 30},
"person2": {"name": "Bob", "age": 25},
}
for person_id, details in people.items():
print(f"{person_id}:")
for key, value in details.items():
print(f" {key}: {value}")Saída:
person1:
name: Alice
age: 30
person2:
name: Bob
age: 25Achatar um dicionário aninhado em uma lista de registros
Um padrão comum ao preparar dados para processamento:
people = {
"person1": {"name": "Alice", "age": 30},
"person2": {"name": "Bob", "age": 25},
}
records = [
{"id": pid, **info}
for pid, info in people.items()
]
print(records)
# [{'id': 'person1', 'name': 'Alice', 'age': 30},
# {'id': 'person2', 'name': 'Bob', 'age': 25}]Dicionários Profundamente Aninhados
Python não impõe limite na profundidade de aninhamento. Aqui está um exemplo de três níveis representando a estrutura de departamentos de uma empresa:
company = {
"engineering": {
"frontend": {
"lead": "Alice",
"headcount": 5,
},
"backend": {
"lead": "Bob",
"headcount": 8,
},
},
"marketing": {
"content": {
"lead": "Carol",
"headcount": 3,
},
},
}
# Access three levels deep
print(company["engineering"]["backend"]["lead"]) # Bob
# Iterate two levels and collect leads
leads = [
dept_data["lead"]
for dept_data in (
team
for teams in company.values()
for team in teams.values()
)
]
print(leads) # ['Alice', 'Bob', 'Carol']Ao ler chaves profundas que podem estar ausentes, encadeie chamadas de .get():
lead = company.get("hr", {}).get("recruitment", {}).get("lead", "Not assigned")
print(lead) # Not assignedDicionários Aninhados e JSON
Objetos JSON mapeiam diretamente para dicionários aninhados em Python. O módulo json converte entre eles:
import json
data = {
"users": {
"u1": {"name": "Alice", "active": True},
"u2": {"name": "Bob", "active": False},
}
}
# Serialize to JSON string
json_str = json.dumps(data, indent=2)
print(json_str)
# Deserialize back to a nested dict
restored = json.loads(json_str)
print(restored["users"]["u1"]["name"]) # AliceEste é o fluxo de trabalho típico ao consumir REST APIs ou ler arquivos de configuração.
Armadilhas Comuns
Armadilha de referência compartilhada. Se você copiar um dicionário interno por referência e depois modificá-lo, tanto o original quanto a cópia serão alterados:
original = {"a": {"x": 1}}
shallow = original.copy() # copies only the outer dict
shallow["a"]["x"] = 99
print(original["a"]["x"]) # 99 ← original is affected!Use copy.deepcopy() quando precisar de uma cópia totalmente independente:
import copy
original = {"a": {"x": 1}}
deep = copy.deepcopy(original)
deep["a"]["x"] = 99
print(original["a"]["x"]) # 1 ← original is safeConsulte o capítulo Copiar Dicionários para uma comparação completa entre cópia rasa e profunda.
KeyError em chaves intermediárias ausentes. Escrever d["a"]["b"] = 1 lança KeyError se "a" ainda não existir. Use setdefault ou collections.defaultdict para criar automaticamente os níveis intermediários.
Referência Rápida
| Tarefa | Sintaxe |
|---|---|
| Acessar valor interno | d["outer"]["inner"] |
| Acesso seguro | d.get("outer", {}).get("inner", default) |
| Adicionar / atualizar chave interna | d["outer"]["inner"] = value |
| Adicionar novo sub-dicionário | d["new_key"] = {...} |
| Excluir chave interna | del d["outer"]["inner"] |
| Excluir sub-dicionário | del d["outer"] |
| Iterar todas as entradas | for k, v in d.items(): for ik, iv in v.items(): |
| Cópia profunda | import copy; copy.deepcopy(d) |