Dicionários em Python (dict): criação, métodos, iteração, ordenação e frozendict
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:
frozendictherda deobject, e não dedict, por issoisinstance(cfg, dict)dáFalse. Para verificar «qualquer dicionário» usecollections.abc.Mappingouisinstance(x, (dict, frozendict)).- Ele é hasheável apenas se as chaves e os valores forem hasheáveis:
frozendict(a=[1])é criado, mashash()falha. A imutabilidade é rasa, como a de uma tupla. - A ordem é preservada, mas
==não a considera. json.dumps,pickleecopyentendem o frozendict.
Erros típicos
- KeyError na leitura — use
getou a verificação comin. - 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()oudeepcopy. {}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.
Perguntas frequentes
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.
Este tema é abordado em profundidade, com prática, no curso “Python 3.15: от новичка до профи”.
Ir para o curso