# Dicionários em Python (dict): criação, métodos, iteração, ordenação e frozendict

URL: https://skillaria.top/pt/guides/python/dicionarios-python-dict

Dicionário em Python (dict) é uma coleção modificável de pares «chave — valor», que encontra o valor pela chave quase instantaneamente; é criado com chaves {"café": 250} ou com a função dict(). As chaves são únicas e precisam ser hasheáveis; desde o Python 3.7 a ordem de inserção é preservada, e no 3.15 surgiu a versão embutida imutável — frozendict.

Dicionário em Python (`dict`) é uma coleção de pares «chave — valor» em que o valor é encontrado pela chave quase instantaneamente, não importa quantos registros existam. Para somar gastos por categoria, guardar configurações ou buscar um usuário pelo id, usa-se um dicionário. A seguir, tudo o que é preciso para trabalhar com o python dict: criação, métodos, iteração, ordenação, junção e a novidade do 3.15 — o `frozendict`.

## O que é um dicionário em Python

O dicionário guarda pares, e cada chave é única: se você gravar um valor numa chave existente, o antigo é substituído. Por dentro é uma tabela de hash, por isso busca, inserção e remoção por chave funcionam, em média, em tempo constante, e não por varredura.

Como chave só pode ser usado um objeto hasheável: string, número, tupla de valores imutáveis. Uma lista não pode ser chave — você receberá `TypeError: unhashable type: 'list'`. Já os valores podem ser quaisquer, inclusive outros dicionários e listas.

A partir do Python 3.7 o dicionário mantém com garantia a ordem de inserção: ao percorrê-lo, as chaves aparecem na ordem em que foram adicionadas.

## Como criar um dicionário

Há várias formas de criar um dicionário, e todas aparecem em código real.

```
spent = {"Alimentação": 1200, "Táxi": 450}   # literal
empty = {}                                   # dicionário vazio
also_empty = dict()                          # o mesmo, pela função dict
user = dict(name="Ana", age=30)              # argumentos nomeados
pairs = dict([("a", 1), ("b", 2)])           # a partir de uma lista de pares
keys = dict.fromkeys(["x", "y"], 0)          # {'x': 0, 'y': 0}
```

Repare: chaves vazias `{}` criam justamente um dicionário vazio, e não um conjunto. Um conjunto vazio é criado somente com `set()`.

Uma forma cômoda de montar um dicionário a partir de duas listas é o `zip`:

```
names = ["Alimentação", "Táxi", "Cinema"]
sums = [1200, 450, 600]
spent = dict(zip(names, sums))
print(spent)   # {'Alimentação': 1200, 'Táxi': 450, 'Cinema': 600}
```

## Acesso pela chave: d[k] e get

O valor é lido com colchetes. Se a chave não existir, o Python lança `KeyError`. Para não ter esse erro, use o método `get`: ele devolve `None` ou um valor padrão.

```
spent = {"Alimentação": 1200}
print(spent["Alimentação"])        # 1200
print(spent.get("Cinema"))         # None
print(spent.get("Cinema", 0))      # 0
spent["Cinema"]                    # KeyError: 'Cinema'
```

Para verificar se uma chave existe, use o operador `in`: `"Alimentação" in spent` devolve `True`. Ele verifica justamente as chaves, e não os valores. Para valores escreva `1200 in spent.values()`.

## Inclusão, alteração e remoção

Adicionar ou atualizar um registro é uma única linha de atribuição. Para contagens é muito útil combinar com `get`:

```
spent = {}
for category, amount in [("Alimentação", 250), ("Táxi", 300), ("Alimentação", 400)]:
    spent[category] = spent.get(category, 0) + amount
print(spent)   # {'Alimentação': 650, 'Táxi': 300}
```

Remover uma chave é possível com `del d[k]` (lança `KeyError` se a chave não existir) ou com `d.pop(k, default)`, que ainda devolve o valor. Para esvaziar o dicionário por completo use `d.clear()`. O tamanho do dicionário, ou seja, o número de pares, é dado por `len(d)`.

## Métodos de dicionário: resumo

| Método | O que faz |
| --- | --- |

| `get(k, default)` | valor da chave ou default, sem erro |

| `setdefault(k, default)` | devolve o valor; se a chave não existir, grava antes o default |

| `update(other)` | acrescenta e sobrescreve pares de outro dicionário |

| `pop(k, default)` | remove a chave e devolve o valor |

| `popitem()` | remove e devolve o último par adicionado |

| `keys()`, `values()`, `items()` | visões das chaves, dos valores e dos pares |

| `copy()` | cópia rasa |

| `clear()` | esvazia o dicionário |

| `fromkeys(keys, value)` | novo dicionário com o mesmo valor para todas as chaves |

### setdefault: preencher o dicionário com listas

O método `setdefault` ajuda quando os valores são listas e é preciso agrupar:

```
groups = {}
for item, cat in [("café", "Alimentação"), ("metrô", "Transporte"), ("pizza", "Alimentação")]:
    groups.setdefault(cat, []).append(item)
print(groups)   # {'Alimentação': ['café', 'pizza'], 'Transporte': ['metrô']}
```

### update: atualizar o dicionário

`update` altera o dicionário no próprio lugar: chaves novas são acrescentadas, e as coincidentes são sobrescritas.

```
cfg = {"debug": False, "lang": "pt"}
cfg.update({"debug": True, "theme": "dark"})
print(cfg)   # {'debug': True, 'lang': 'pt', 'theme': 'dark'}
```

## defaultdict: dicionário com valor padrão

`collections.defaultdict` é uma subclasse de dict que, ao acessar uma chave inexistente, cria o valor sozinho por meio de uma fábrica. O código de contagens e agrupamentos fica mais curto.

```
from collections import defaultdict

spent = defaultdict(int)
for cat, amount in [("Alimentação", 250), ("Táxi", 300), ("Alimentação", 400)]:
    spent[cat] += amount
print(dict(spent))   # {'Alimentação': 650, 'Táxi': 300}

groups = defaultdict(list)
groups["Alimentação"].append("café")
```

Para contar ocorrências de forma simples existe ainda `collections.Counter`: `Counter(["a", "b", "a"])` devolve `Counter({'a': 2, 'b': 1})`.

## Iteração sobre um dicionário: laço for

O laço `for` sobre um dicionário percorre, por padrão, as chaves. Para obter chave e valor de uma vez, itere sobre `items()` — é a variante mais comum.

```
spent = {"Alimentação": 650, "Táxi": 300}

for cat in spent:                    # chaves
    print(cat)

for amount in spent.values():        # valores
    print(amount)

for cat, amount in spent.items():    # pares
    print(f"{cat}: R$ {amount}")
```

Alterar o tamanho do dicionário durante a iteração não é permitido — ocorrerá `RuntimeError: dictionary changed size during iteration`. Se for preciso remover parte das chaves, percorra uma cópia: `for k in list(d):`.

## Exibir um dicionário na tela

`print(d)` imprime o dicionário em uma linha só. Para dicionários grandes ou aninhados é mais prático o módulo `pprint` ou `json.dumps(d, ensure_ascii=False, indent=2)` — ele exibe os dados com recuo e com acentos sem escape.

## Ordenação de dicionário

O próprio dicionário não é ordenado no lugar: ele não tem método `sort`. Ordenar um dicionário significa criar um novo a partir dos pares ordenados com `sorted`.

```
spent = {"Táxi": 300, "Alimentação": 650, "Cinema": 120}

by_key = dict(sorted(spent.items()))
print(by_key)    # {'Alimentação': 650, 'Cinema': 120, 'Táxi': 300}

by_value = dict(sorted(spent.items(), key=lambda p: p[1], reverse=True))
print(by_value)  # {'Alimentação': 650, 'Táxi': 300, 'Cinema': 120}
```

Se precisar apenas das N categorias principais, não converta o resultado de volta em dicionário: `sorted(spent.items(), key=lambda p: p[1], reverse=True)[:2]` devolve uma lista de pares.

Ordenar uma lista de dicionários por um campo é simples: `sorted(users, key=lambda u: u["age"])`.

## Junção e soma de dicionários

A partir do Python 3.9, os dicionários se unem com o operador `|`, e `|=` atualiza o dicionário no próprio lugar. Quando as chaves coincidem, vence o operando da direita.

```
a = {"x": 1, "y": 2}
b = {"y": 20, "z": 3}
print(a | b)          # {'x': 1, 'y': 20, 'z': 3}
print({**a, **b})     # o mesmo, com desempacotamento
a |= b                # como a.update(b)
```

Atenção: `a + b` para dicionários não funciona e gera `TypeError`. Se for preciso somar os valores das chaves iguais, use `Counter`: `Counter(a) + Counter(b)`.

### Desempacotamento de dicionário

Dois asteriscos `**` desempacotam um dicionário em argumentos nomeados de uma função ou em outro dicionário:

```
def greet(name, city):
    return f"{name} de {city}"

data = {"name": "Ana", "city": "Recife"}
print(greet(**data))   # Ana de Recife
```

## Dict comprehension

A comprehension de dicionário monta um dicionário em uma linha a partir de qualquer sequência:

```
squares = {n: n * n for n in range(5)}
print(squares)   # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

big = {k: v for k, v in spent.items() if v > 200}

inverted = {v: k for k, v in {"a": 1, "b": 2}.items()}
print(inverted)  # {1: 'a', 2: 'b'}
```

O último exemplo mostra como inverter um dicionário, trocando chaves e valores de lugar. Funciona se os valores forem únicos e hasheáveis; caso contrário, parte dos pares se perde.

## Dicionários aninhados

O valor pode ser outro dicionário — assim se descrevem estruturas como respostas JSON de APIs ou um dicionário de usuários.

```
users = {
    101: {"name": "Ana", "skills": ["python", "sql"]},
    102: {"name": "Oscar", "skills": ["go"]},
}
print(users[101]["skills"][0])            # python
print(users.get(103, {}).get("name"))     # None, sem KeyError
```

## Cópia de dicionário: cópia e segundo nome

A linha `b = a` não copia o dicionário: ela apenas dá um segundo nome ao mesmo objeto. Altere algo por `b` — e a mudança aparecerá em `a`. O mesmo acontece ao passar um dicionário para uma função: ela recebe a referência ao objeto comum e pode estragá-lo sem avisar.

```
import copy

a = {"limits": [0, 500]}
b = a.copy()              # cópia rasa
b["limits"].append(1000)  # a lista interna é compartilhada!
print(a)                  # {'limits': [0, 500, 1000]}

c = copy.deepcopy(a)      # cópia completa e independente
```

## Comparação de dicionários

O operador `==` compara dicionários pelo conteúdo: são iguais se todos os pares coincidem. A ordem das chaves não é considerada: `{"a": 1, "b": 2} == {"b": 2, "a": 1}` dá `True`. Para encontrar chaves em comum, use operações de conjunto sobre as visões: `a.keys() & b.keys()`.

## Dicionário tipado: anotações

A anotação de dicionário escreve-se como `dict[str, int]`. Se o dicionário tem um conjunto fixo de campos de tipos diferentes, é cômodo o `TypedDict` do módulo `typing`:

```
from typing import TypedDict

class User(TypedDict):
    name: str
    age: int

u: User = {"name": "Ana", "age": 30}
```

As anotações não são verificadas durante a execução; elas são lidas pelas IDEs e por analisadores como o mypy.

## Dicionário imutável: frozendict no Python 3.15

No Python 3.15 surgiu o tipo embutido `frozendict` (PEP 814): não é preciso importar nada, e a tentativa de alterá-lo termina imediatamente em `TypeError`. Antes, um dicionário imutável precisava ser imitado com um invólucro do módulo `types` ou com um pacote de terceiros. É exatamente o que serve para configurações comuns, que nenhuma função deve alterar silenciosamente.

```
config = frozendict(min_amount=0, max_amount=500)
config["max_amount"] = 1000
# TypeError: 'frozendict' object does not support item assignment

strict = config | {"max_amount": 300}   # novo frozendict, o original permanece
cache = {config: "relatório de maio"}   # hasheável — serve como chave
```

O que é importante saber, segundo o material do curso:

- `frozendict` herda de `object`, e não de `dict`, por isso `isinstance(cfg, dict)` dá `False`. Para verificar «qualquer dicionário» use `collections.abc.Mapping` ou `isinstance(x, (dict, frozendict))`.
- Ele é hasheável apenas se as chaves e os valores forem hasheáveis: `frozendict(a=[1])` é criado, mas `hash()` falha. A imutabilidade é rasa, como a de uma tupla.
- A ordem é preservada, mas `==` não a considera.
- `json.dumps`, `pickle` e `copy` entendem o frozendict.

## Erros típicos

- **KeyError** na leitura — use `get` ou a verificação com `in`.
- **Lista como chave** — transforme-a em tupla: `d[tuple(lst)]`.
- **Alterar o dicionário dentro do laço** — percorra `list(d)`.
- **Esperar uma cópia da atribuição** — use `copy()` ou `deepcopy`.
- **`{}` no lugar de conjunto vazio** — isso é um dicionário vazio.

## Resumo

O dict do Python é a principal estrutura de dados da linguagem: busca rápida por chave, ordem de inserção preservada, métodos úteis como `get`, `setdefault` e `update`, iteração por `items()`, ordenação com `sorted` e junção com o operador `|`. Lembre-se da cópia e das chaves hasheáveis, e para configurações no Python 3.15 use o `frozendict`. Dicionários, listas, tuplas e conjuntos são praticados no curso «Python 3.15: do iniciante ao profissional», no exemplo do controle de gastos.

## FAQ

**Dá para guardar valores de tipos diferentes num dicionário?**

Sim, os valores podem ser quaisquer e diferentes entre si dentro de um mesmo dicionário: números, strings, listas, outros dicionários. A restrição vale apenas para as chaves — elas precisam ser hasheáveis.

**Como saber a quantidade de elementos de um dicionário?**

A função len(d) devolve o número de pares chave — valor. Para um dicionário vazio ela dá 0, e o próprio dicionário vazio é falso num if.

**Qual a diferença entre dict e defaultdict?**

O defaultdict é uma subclasse de dict que, ao acessar uma chave inexistente, não lança KeyError, e sim cria o valor com uma fábrica, como int ou list. Fora isso, comporta-se como um dicionário comum.

**Como obter a chave a partir do valor?**

Não existe método direto; é preciso percorrer: next((k for k, v in d.items() if v == value), None). Se essa busca for frequente, é melhor montar um dicionário inverso com {v: k for k, v in d.items()}.

**Como salvar um dicionário em arquivo?**

Mais comumente com o módulo json: json.dump(d, f, ensure_ascii=False, indent=2) num arquivo aberto para escrita, e json.load(f) para leitura. As chaves, nesse caso, viram strings.


---
Source: Skillaria.Top (https://skillaria.top)
