Python Dicionários

Numa lista, você acha um item pela posição: o primeiro, o segundo, o quinto. Mas no balcão da padaria ninguém pergunta "quanto custa o produto número 2?"; pergunta "quanto custa o leite?". Para achar um valor por um nome o Python tem o dicionário (em inglês, dictionary, e no código, dict): cada valor fica guardado junto de uma chave, e é pela chave que você o encontra.

Você vai aprender
  • O que são chave e valor, e como criar um dicionário com {chave: valor}.
  • A ler um valor pela chave: precos["leite"].
  • O KeyError, o erro de pedir uma chave que não existe, e como evitá-lo com get() e in.
  • Que o dicionário guarda a ordem em que as chaves entraram.
  • O que pode ser chave (texto, número, tupla) e o que não pode (lista).
  • Os erros reais de maiúscula, de índice, de ponto e de chave sem aspas.

A ideia: o dicionário de verdade

Num dicionário de papel, você procura a palavra e encontra o significado. Ninguém lê o dicionário inteiro até achar "padaria": vai direto à letra P. A palavra é a chave; o significado é o valor.

A tabela de preços pendurada na padaria funciona igual: à esquerda o nome do produto, à direita o preço.

Chave (o nome)Valor (o que está guardado)
"pão"0.50
"leite"4.75
"café"18.90

Cada linha é um par chave-valor. Em Python, essa tabela inteira cabe numa variável.


1. Criando um dicionário

precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
print(precos)
print(type(precos))
print(len(precos))
{ … }
As chaves envolvem o dicionário inteiro, como no conjunto. O que faz a diferença é o dois-pontos lá dentro.
"pão": 0.50
Um par: a chave "pão", o dois-pontos :, e o valor 0.50. Leia como "pão vale 0.50".
,
A vírgula separa um par do outro.
type(precos)
O tipo se chama dict.
len(precos)
Quantos pares há no dicionário: 3.
$ python3 di_criar.py
{'pão': 0.5, 'leite': 4.75, 'café': 18.9}
<class 'dict'>
3

O Python mostrou 0.5 e 18.9, sem o zero do fim: para ele, 0.50 e 0.5 são o mesmo número. Para mostrar com duas casas, use a f-string com :.2f, como na próxima seção.

Dicionário grande: um par por linha

Quando há muitos pares, o costume é escrever um por linha, com 4 espaços na frente. A vírgula depois do último é permitida e facilita acrescentar outro depois:

precos = {
    "pão": 0.50,
    "leite": 4.75,
    "café": 18.90,
}

2. Lendo um valor pela chave

Para pegar um valor, escreva o nome do dicionário e a chave entre colchetes, como o índice de uma lista, só que com a chave no lugar do número:

precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
print(precos["leite"])
print(f"O café custa R$ {precos['café']:.2f}")
total = precos["pão"] * 10 + precos["leite"]
print(f"Total: R$ {total:.2f}")
$ python3 di_acessar.py
4.75
O café custa R$ 18.90
Total: R$ 9.75
precos["leite"]
"O valor guardado na chave "leite"": 4.75.
{precos['café']:.2f}
Dentro de uma f-string com aspas duplas, a chave vai com aspas simples, para não fechar o texto antes da hora (veja f-strings).
precos["pão"] * 10 + precos["leite"]
O valor lido é um número comum: dá para fazer contas. Dez pães e um leite: R$ 9.75.

Missão: troque o 0 pela leitura do preço do café no dicionário, para o programa mostrar Café: R$ 18.90.

precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
print(f"Café: R$ {0:.2f}")
precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
print(f"Café: R$ {precos['café']:.2f}")

3. A chave que não existe: KeyError

A padaria não vende bolo. O que acontece se o programa pedir o preço do bolo?

precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
print(precos["bolo"])
$ python3 di_keyerror.py
Traceback (most recent call last):
  File "/home/ana/di_keyerror.py", line 2, in <module>
    print(precos["bolo"])
          ~~~~~~^^^^^^^^
KeyError: 'bolo'
Traceback (most recent call last):
Deu erro; abaixo vem onde.
File "/home/ana/di_keyerror.py", line 2
Na linha 2 do programa.
~~~~~~^^^^^^^^
Os ^ apontam para ["bolo"]: a chave pedida.
KeyError: 'bolo'
"Erro de chave": a chave 'bolo' não existe no dicionário. A mensagem é só o nome da chave que faltou, e é a pista para você saber qual foi.

Com colchetes, o dicionário é rigoroso: chave que não existe é erro, e o programa para. Há duas formas de perguntar com cuidado.

Forma 1: get(), que não dá erro

precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
print(precos.get("leite"))
print(precos.get("bolo"))
print(precos.get("bolo", 0))
print(precos.get("bolo", "não temos"))
$ python3 di_get.py
4.75
None
0
não temos
precos.get("leite")
"Pegar": com a chave existindo, é igual a precos["leite"].
precos.get("bolo")
Com a chave faltando, em vez de erro, devolve None ("nada", aula O Valor None).
precos.get("bolo", 0)
O segundo valor é o padrão: o que devolver se a chave não existir. Aqui, 0.
precos.get("bolo", "não temos")
O padrão pode ser qualquer coisa, até um texto.

Forma 2: perguntar antes com in

precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
print("pão" in precos)
print("bolo" in precos)
print("bolo" not in precos)
print(4.75 in precos)
$ python3 di_in.py
True
False
True
False

Repare na última linha: 4.75 in precos deu False, embora 4.75 seja o preço do leite. O in num dicionário procura só nas chaves, nunca nos valores. Para procurar nos valores existe precos.values(), da aula Percorrendo um Dicionário.

Missão: o programa mostra quantos pães e quantos bolos há no estoque, mas para com KeyError: 'bolo', porque bolo não está no dicionário. Use get() com o padrão 0 para mostrar Bolos: 0.

estoque = {"pão": 40, "leite": 12}
print("Pães:", estoque["pão"])
print("Bolos:", estoque["bolo"])
estoque = {"pão": 40, "leite": 12}
print("Pães:", estoque.get("pão", 0))
print("Bolos:", estoque.get("bolo", 0))

4. A ordem é a de chegada

Ao contrário do conjunto, o dicionário lembra a ordem em que as chaves entraram. A Ana montou a agenda acrescentando um contato de cada vez (o jeito de acrescentar, agenda["Bia"] = …, é o assunto da próxima aula):

agenda = {}
agenda["Bia"] = "99999-0002"
agenda["Ana"] = "99999-0001"
agenda["Caio"] = "99999-0003"
print(agenda)
$ python3 di_ordem.py
{'Bia': '99999-0002', 'Ana': '99999-0001', 'Caio': '99999-0003'}

A Bia entrou primeiro e aparece primeiro, em toda execução. Não é ordem alfabética: é a ordem de inserção. O Python garante isso desde a versão 3.7. Mesmo assim, o dicionário não tem posição: não existe agenda[0] (veja Quando dá errado); a ordem só aparece quando você mostra ou percorre o dicionário.


5. O que pode ser chave, o que pode ser valor

alunos = {101: "Ana", 102: "Bia"}
print(alunos[101])
distancias = {("Teresina", "Picos"): 306}
print(distancias[("Teresina", "Picos")])
repetida = {"pão": 0.50, "pão": 0.60}
print(repetida)
ficha = {"nome": "Ana", "idade": 34, "notas": [9, 7, 10], "vip": True}
print(ficha["notas"])
$ python3 di_chaves.py
Ana
306
{'pão': 0.6}
[9, 7, 10]
{101: "Ana", 102: "Bia"}
Números podem ser chave: aqui, o número de matrícula. alunos[101] não é "a posição 101", é "a chave 101".
{("Teresina", "Picos"): 306}
Uma tupla pode ser chave: a distância em km entre duas cidades.
{"pão": 0.50, "pão": 0.60}
Cada chave existe uma vez só. Escrita duas vezes, vale a última: sobrou 0.6. Não é erro, por isso é fácil não perceber.
ficha
Os valores podem ser de qualquer tipo, misturados: texto, número, lista, True. Um dicionário assim descreve uma coisa (a ficha da Ana) campo por campo.

A regra para as chaves é a mesma dos itens de um conjunto: só valores que não mudam (texto, número, tupla, True/False). Lista não pode ser chave. Os valores, esses, podem ser qualquer coisa, até outro dicionário (aula Dicionários Aninhados).


6. Outras formas de criar: dict()

a = dict(pao=0.50, leite=4.75)
print(a)
b = dict([("pão", 0.50), ("leite", 4.75)])
print(b)
vazio = {}
tambem = dict()
print(vazio, tambem, len(vazio))
$ python3 di_dict.py
{'pao': 0.5, 'leite': 4.75}
{'pão': 0.5, 'leite': 4.75}
{} {} 0
FormaQuando usar
{"pão": 0.50, "leite": 4.75}Quase sempre. É a forma mais comum e a mais clara
dict(pao=0.50, leite=4.75)Quando as chaves são textos simples, que poderiam ser nomes de variável (sem espaço, sem começar com número). Repare que aqui a chave virou 'pao', sem til, porque a Ana escreveu assim
dict([("pão", 0.50), ("leite", 4.75)])Quando os pares já estão numa lista de tuplas
{} ou dict()Dicionário vazio, para encher depois

Lista ou dicionário?

SituaçãoUse
Uma fila de coisas do mesmo tipo, em que a posição importa (as tarefas do dia, em ordem)Lista
Você procura pelo nome (o preço de cada produto, o telefone de cada pessoa)Dicionário
Os campos de uma ficha (nome, idade, cidade)Dicionário

Quando dá errado

Chave com maiúscula diferente
precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
print(precos["Leite"])
$ python3 di_maiuscula.py
Traceback (most recent call last):
  File "/home/ana/di_maiuscula.py", line 2, in <module>
    print(precos["Leite"])
          ~~~~~~^^^^^^^^^
KeyError: 'Leite'

Para o dicionário, "Leite" e "leite" são chaves diferentes, como "cafe" e "café". A chave tem de ser igual letra por letra. Como consertar: escreva a chave exatamente como foi guardada. Se a chave vem do teclado, padronize antes: precos[item.lower()] (aula Métodos de Texto).

Pedir pela posição
precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
print(precos[0])
$ python3 di_indice.py
Traceback (most recent call last):
  File "/home/ana/di_indice.py", line 2, in <module>
    print(precos[0])
          ~~~~~~^^^
KeyError: 0

Não é IndexError, como seria numa lista: é KeyError: 0. O dicionário procurou uma chave chamada 0 e não achou. No dicionário, o que vai entre colchetes é sempre uma chave, nunca uma posição. Como consertar: peça pela chave (precos["pão"]). Para "o primeiro par", percorra o dicionário (próximas aulas).

Chave sem aspas
precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
print(precos[leite])
$ python3 di_semaspas.py
Traceback (most recent call last):
  File "/home/ana/di_semaspas.py", line 2, in <module>
    print(precos[leite])
                 ^^^^^
NameError: name 'leite' is not defined

Sem aspas, leite é o nome de uma variável, e não existe nenhuma variável com esse nome: "nome 'leite' não está definido". Como consertar: chave de texto vai entre aspas: precos["leite"]. (Sem aspas só faz sentido quando existe mesmo uma variável guardando a chave, como item = "leite" e depois precos[item].)

Ponto no lugar dos colchetes
precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
print(precos.leite)
$ python3 di_ponto.py
Traceback (most recent call last):
  File "/home/ana/di_ponto.py", line 2, in <module>
    print(precos.leite)
          ^^^^^^^^^^^^
AttributeError: 'dict' object has no attribute 'leite'

Quem vem do JavaScript costuma escrever precos.leite. Em Python, o ponto serve para os métodos (precos.get), e o dicionário não tem nada chamado leite. Como consertar: precos["leite"].

Lista como chave
estoque = {["arroz", "5kg"]: 12}
$ python3 di_lista_chave.py
Traceback (most recent call last):
  File "/home/ana/di_lista_chave.py", line 1, in <module>
    estoque = {["arroz", "5kg"]: 12}
              ^^^^^^^^^^^^^^^^^^^^^^
TypeError: cannot use 'list' as a dict key (unhashable type: 'list')

"Não é possível usar list como chave de dicionário". A lista pode mudar, e uma chave que muda deixaria o dicionário perdido. Como consertar: use uma tupla: {("arroz", "5kg"): 12}. (No Python 3.13 a mensagem é só TypeError: unhashable type: 'list'; a primeira parte é novidade da 3.14.)


Referência rápida

EscritaO que faz
d = {"a": 1, "b": 2}Cria um dicionário
d = {} / dict()Dicionário vazio
d["a"]O valor da chave "a"; KeyError se não existir
d.get("a")O valor, ou None se a chave não existir
d.get("a", 0)O valor, ou 0 se a chave não existir
"a" in dTrue se a chave existe
len(d)Quantos pares chave-valor
dict(pao=1), dict([("pão", 1)])Outras formas de criar
MensagemCausa provável
KeyError: 'bolo'A chave não existe (ou está escrita diferente: maiúscula, acento)
KeyError: 0Pediu por posição: dicionário não tem índice
NameError: name 'leite' is not definedChave de texto sem aspas
AttributeError: 'dict' object has no attribute 'leite'd.leite no lugar de d["leite"]
TypeError: cannot use 'list' as a dict key …Lista como chave: use tupla
Um par sumiu, sem erroChave repetida na criação: vale a última

Exercícios

1. Lendo o preço

Complete para mostrar o preço do pão:

print(precos)

2. Sem erro

Complete o método que devolve 0 se a chave "bolo" não existir:

qtd = estoque.("bolo", 0)

3. Quantos pares?

Quanto vale len({"a": 1, "b": 2, "a": 3})?

4. Com precos = {"pão": 0.50, "leite": 4.75}, o que 0.50 in precos responde?

5. O que {"x": 1}["y"] causa?

6. Qual destes não pode ser chave de um dicionário?

Missão final: o balcão da padaria

Missão: o cliente digita o nome de um produto (a caixa já vai responder leite por ele). Se o produto estiver no dicionário, mostre leite custa R$ 4.75; se não estiver, mostre Não temos …. Use in para perguntar antes, sem deixar o programa parar com KeyError.

precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
item = input("Qual produto? ")
print("?")
precos = {"pão": 0.50, "leite": 4.75, "café": 18.90}
item = input("Qual produto? ")
if item in precos:
    print(f"{item} custa R$ {precos[item]:.2f}")
else:
    print(f"Não temos {item}.")

A Ana salvou a solução como balcao.py e rodou no terminal duas vezes; na primeira digitou leite, na segunda bolo:

$ python3 balcao.py
Qual produto? leite
leite custa R$ 4.75
$ python3 balcao.py
Qual produto? bolo
Não temos bolo.

Resumo

  • O dicionário (dict) guarda pares chave: valor: {"pão": 0.50, "leite": 4.75}.
  • Lê-se pela chave, com colchetes: precos["leite"]. Chave que não existe dá KeyError.
  • get(chave, padrão) devolve o padrão (ou None) em vez de dar erro; chave in d pergunta se a chave existe (só olha as chaves).
  • O dicionário guarda a ordem de inserção, mas não tem índice: d[0] procura a chave 0.
  • Cada chave aparece uma vez; repetida, vale a última. Chaves: texto, número, tupla (lista não). Valores: qualquer coisa.
  • A chave tem de ser exata: "Leite" não é "leite".