W3docs

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 evitar KeyError
  • 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:

python— editable, runs on the server

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:

python— editable, runs on the server

Adicionando Novos Sub-Dicionários

Atribua um novo dicionário literal a uma nova chave externa:

python— editable, runs on the server

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: 25

Achatar 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 assigned

Dicioná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"])  # Alice

Este é 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 safe

Consulte 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

TarefaSintaxe
Acessar valor internod["outer"]["inner"]
Acesso segurod.get("outer", {}).get("inner", default)
Adicionar / atualizar chave internad["outer"]["inner"] = value
Adicionar novo sub-dicionáriod["new_key"] = {...}
Excluir chave internadel d["outer"]["inner"]
Excluir sub-dicionáriodel d["outer"]
Iterar todas as entradasfor k, v in d.items(): for ik, iv in v.items():
Cópia profundaimport copy; copy.deepcopy(d)

Prática

Prática
Which method safely reads a missing key from a nested dict without raising a KeyError?
Which method safely reads a missing key from a nested dict without raising a KeyError?
Was this page helpful?