Pular para o conteúdo principal

Aula 10: Dicionários


Objetivos de Aprendizagem

Ao final desta aula, você será capaz de:

  1. Criar dicionários em Python e acessar valores por chave
  2. Adicionar, modificar e remover pares chave-valor
  3. Utilizar os métodos .keys(), .values(), .items(), .get() e .update()
  4. Iterar sobre dicionários de diferentes formas
  5. Escolher entre lista e dicionário conforme o problema

Conteúdo Teórico

1. O Problema que os Dicionários Resolvem

Imagine que você precisa armazenar dados de um aluno: nome, matrícula, curso e média. Com listas:

aluno = ["Maria", "2024001", "Ciência da Computação", 8.5]
# Para acessar a média, você precisa saber que ela está no índice 3
print(aluno[3]) # 8.5 — mas o índice não explica o que é esse valor

Com um dicionário, cada dado recebe um rótulo (chave) que explica seu significado:

aluno = {
"nome": "Maria",
"matricula": "2024001",
"curso": "Ciência da Computação",
"media": 8.5
}
print(aluno["media"]) # 8.5 — a chave explica o que estamos acessando
Conceito Fundamental

Um dicionário é uma estrutura de dados que armazena pares chave → valor. Cada chave é única dentro do dicionário e serve como identificador para acessar o valor correspondente. Em outras linguagens, estruturas equivalentes são chamadas de hash map, hash table ou associative array.


2. Criando Dicionários

Dicionários são delimitados por chaves {}. Cada par é escrito como chave: valor, separado por vírgulas:

# Dicionário com dados de um produto
produto = {
"nome": "Notebook",
"preco": 3500.00,
"estoque": 15,
"disponivel": True
}

# Dicionário vazio
configuracoes = {}

# Criando com a função dict()
cores = dict(vermelho="#FF0000", verde="#00FF00", azul="#0000FF")

Regras para chaves:

  • Chaves devem ser de um tipo imutável: str, int, float, tuple
  • O tipo mais comum e recomendado é str (facilita a leitura)
  • Chaves são únicas — definir a mesma chave duas vezes sobrescreve o valor anterior
  • Valores podem ser de qualquer tipo, incluindo listas e outros dicionários

3. Acessando e Modificando Valores

Acesso por chave

aluno = {"nome": "Maria", "media": 8.5, "curso": "BCC"}

print(aluno["nome"]) # Maria
print(aluno["media"]) # 8.5

Acessar uma chave inexistente gera um KeyError:

print(aluno["idade"]) # KeyError: 'idade'

Método .get() — acesso seguro

.get(chave) retorna None se a chave não existir, evitando o erro:

print(aluno.get("idade")) # None
print(aluno.get("idade", 0)) # 0 — valor padrão definido pelo programador

Verificar existência com in

print("nome" in aluno) # True
print("idade" in aluno) # False

Adicionar e modificar

aluno["matricula"] = "2024001" # adiciona nova chave
aluno["media"] = 9.0 # modifica valor existente
print(aluno)
# {"nome": "Maria", "media": 9.0, "curso": "BCC", "matricula": "2024001"}

Remover pares

del aluno["curso"] # remove o par — KeyError se não existir
valor = aluno.pop("media") # remove e retorna o valor
print(valor) # 9.0

4. Iterando sobre Dicionários

Iterando sobre chaves (padrão)

produto = {"nome": "Notebook", "preco": 3500.0, "estoque": 15}

for chave in produto:
print(chave)
# nome
# preco
# estoque

.keys(), .values() e .items()

MétodoRetorna
.keys()Sequência de todas as chaves
.values()Sequência de todos os valores
.items()Sequência de tuplas (chave, valor)
for chave in produto.keys():
print(chave)

for valor in produto.values():
print(valor)

for chave, valor in produto.items():
print(f"{chave}: {valor}")
# nome: Notebook
# preco: 3500.0
# estoque: 15
Dica prática

.items() é o método mais usado em iterações porque fornece chave e valor juntos, eliminando a necessidade de um segundo acesso produto[chave].


5. Outros Métodos Úteis

config = {"tema": "escuro", "idioma": "pt-BR", "fonte": 14}

# .update() — mescla outro dicionário (ou pares chave=valor)
config.update({"fonte": 16, "zoom": 100})
print(config)
# {"tema": "escuro", "idioma": "pt-BR", "fonte": 16, "zoom": 100}

# len() — número de pares
print(len(config)) # 4

# .clear() — remove todos os pares
backup = dict(config) # cópia antes de limpar
config.clear()
print(config) # {}

6. Exemplo Prático: Contagem de Frequência

Um uso clássico de dicionários é contar ocorrências:

texto = "abracadabra"
frequencia = {}

for letra in texto:
if letra in frequencia:
frequencia[letra] += 1
else:
frequencia[letra] = 1

print(frequencia)
# {'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}

O mesmo resultado com .get():

frequencia = {}
for letra in texto:
frequencia[letra] = frequencia.get(letra, 0) + 1

7. Lista vs. Dicionário — Quando Usar Cada Um?

CritérioListaDicionário
AcessoPor índice numéricoPor chave descritiva
SemânticaSequência de itens similaresRegistro com atributos nomeados
OrdemPreservada (Python 3.7+)Preservada (Python 3.7+)
Busca por chaveO(n) — percorre tudoO(1) — acesso direto
Exemplo típico[nota1, nota2, nota3]{"nome": "João", "nota": 8.0}

Use lista quando os elementos são da mesma natureza e a posição importa (notas, dias, produtos).

Use dicionário quando cada dado tem um nome (atributo) e você acessa pelo rótulo (aluno, configuração, produto).


Exercícios / Checkpoints

Checkpoint 1: Criação e acesso

Crie um dicionário representando um livro com as chaves: titulo, autor, ano e paginas. Imprima cada valor acessando pela chave. Em seguida, tente acessar uma chave inexistente usando .get() com um valor padrão de sua escolha.

Checkpoint 2: Modificação

Dado o dicionário abaixo, faça as operações indicadas e imprima o resultado após cada uma:

estoque = {"arroz": 50, "feijão": 30, "macarrão": 20}
  1. Adicione "sal" com quantidade 100
  2. Atualize a quantidade de "feijão" para 45
  3. Remova "macarrão" e capture o valor removido em uma variável

Checkpoint 3: Iteração com .items()

Escreva um programa que imprima o inventário abaixo no formato "Produto: X | Quantidade: Y | Total: R$ Z", onde Total = quantidade × preco:

produtos = {
"caneta": {"quantidade": 100, "preco": 2.50},
"caderno": {"quantidade": 30, "preco": 15.90},
"borracha": {"quantidade": 75, "preco": 1.20},
}

Checkpoint 4: Contagem de frequência

Escreva um programa que leia uma frase e conte quantas vezes cada palavra aparece. Imprima as palavras e suas contagens em ordem alfabética. (Dica: frase.split() separa a string em lista de palavras; sorted(dicionario) ordena as chaves.)

Checkpoint 5: Lista vs. Dicionário

Para cada situação abaixo, justifique se usaria uma lista ou um dicionário:

  1. Armazenar as temperaturas de uma cidade ao longo de 30 dias
  2. Armazenar os dados de um funcionário (nome, CPF, cargo, salário)
  3. Armazenar os 10 filmes mais assistidos na plataforma (em ordem)
  4. Armazenar o placar de cada jogador em um jogo

Situações Problema

As duas situações abaixo são para implementação em aula. Elas exigem a combinação de vários conceitos da aula — não há uma única solução certa. Incentive os alunos a experimentar, errar e discutir abordagens diferentes.


Situação Problema 1: Apuração de Votos em Eleição de Representante

Contexto: Uma turma está elegendo seu representante discente. Cada aluno escreveu o nome do candidato de sua preferência em um papel. Os votos foram digitados na lista abaixo. Votos nulos são identificados pela string "nulo".

Código inicial:

votos = [
"Alice", "Bruno", "Alice", "nulo", "Carlos", "Alice",
"Bruno", "nulo", "Carlos","Bruno", "Alice", "Carlos",
"Bruno", "Alice", "nulo", "Bruno", "Carlos", "Alice",
]

Tarefas:

  1. Contabilize os votos de cada candidato, ignorando os nulos na contagem por candidato (registre o total de nulos separado).
  2. Determine o(s) vencedor(es) — quem obteve mais votos válidos.
  3. Exiba o resultado completo: total de votos válidos, percentual de cada candidato e o nome do vencedor. Mostre os candidatos em ordem decrescente de votos.
  4. Detecte empate: se dois ou mais candidatos dividirem o primeiro lugar, liste todos e informe que haverá segundo turno.
Nota rápida sobre key=lambda

No trecho sorted(contagem.items(), key=lambda par: par[1], reverse=True), key= define o critério de ordenação e lambda par: par[1] significa: "para cada par (chave, valor), use o valor (par[1]) para ordenar".

Dica para a tarefa 3

Para ordenar um dicionário por valor decrescente:

sorted(contagem.items(), key=lambda par: par[1], reverse=True)

Saída esperada:

Total de votos: 18
Votos válidos : 15
Votos nulos : 3

Resultado (ordem decrescente):
Alice: 6 voto(s) — 40.0%
Bruno: 5 voto(s) — 33.3%
Carlos: 4 voto(s) — 26.7%

Vencedor: Alice com 6 voto(s).
Ver solução
# Tarefa 1: contabilizar votos (excluindo nulos)
contagem = {}
total_nulos = 0

for voto in votos:
if voto == "nulo":
total_nulos += 1
else:
contagem[voto] = contagem.get(voto, 0) + 1

# Tarefa 2: determinar vencedor(es)
total_validos = sum(contagem.values())
max_votos = 0
for qtd in contagem.values():
if qtd > max_votos:
max_votos = qtd

vencedores = []
for candidato, qtd in contagem.items():
if qtd == max_votos:
vencedores.append(candidato)

# Tarefa 3: resultado em ordem decrescente de votos
print(f"Total de votos: {len(votos)}")
print(f"Votos válidos : {total_validos}")
print(f"Votos nulos : {total_nulos}")
print("\nResultado (ordem decrescente):")
for candidato, qtd in sorted(contagem.items(), key=lambda par: par[1], reverse=True):
percentual = qtd / total_validos * 100
print(f" {candidato}: {qtd} voto(s) — {percentual:.1f}%")

# Tarefa 4: detectar empate
print()
if len(vencedores) > 1:
print(f"Empate! Haverá segundo turno entre: {', '.join(vencedores)}.")
else:
print(f"Vencedor: {vencedores[0]} com {max_votos} voto(s).")

Situação Problema 2: Controle de Estoque com Relatório de Vendas

Contexto: Uma pequena loja registrou todas as transações do dia. Cada transação é um dicionário com produto, quantidade vendida e preço unitário. O estoque inicial de cada produto é fornecido separadamente.

Código inicial:

transacoes = [
{"produto": "caneta", "quantidade": 12, "preco": 2.50},
{"produto": "caderno", "quantidade": 5, "preco": 15.90},
{"produto": "caneta", "quantidade": 8, "preco": 2.50},
{"produto": "borracha", "quantidade": 20, "preco": 1.20},
{"produto": "caderno", "quantidade": 3, "preco": 15.90},
{"produto": "caneta", "quantidade": 5, "preco": 2.50},
{"produto": "mochila", "quantidade": 2, "preco": 89.90},
{"produto": "borracha", "quantidade": 15, "preco": 1.20},
]

estoque_inicial = {
"caneta": 50, "caderno": 15, "borracha": 40, "mochila": 5
}

Tarefas:

  1. Calcule o total de unidades vendidas e o faturamento por produto. Armazene em um dicionário no formato {"caneta": {"unidades": 25, "faturamento": 62.50}, ...}. Atenção: o mesmo produto aparece em múltiplas transações.
  2. Identifique o produto mais vendido (por unidades) e o de maior faturamento (podem ser diferentes).
  3. Partindo do estoque inicial, calcule o estoque restante e liste os produtos abaixo do estoque mínimo de 5 unidades.
  4. Exiba um relatório formatado com todas as informações acima.
Dica para a tarefa 1

Use .get() ou verifique a existência da chave antes de acumular — o mesmo produto aparece em múltiplas linhas de transação.

Saída esperada:

====================================================
RELATÓRIO DE VENDAS
====================================================
Produto | Unidades | Faturamento
----------------------------------------------------
caneta | 25 | R$ 62.50
caderno | 8 | R$ 127.20
borracha | 35 | R$ 42.00
mochila | 2 | R$ 179.80
----------------------------------------------------

Mais vendido (unidades) : borracha (35 un.)
Maior faturamento : mochila (R$ 179.80)

Estoque restante:
caneta : 25 un.
caderno : 7 un.
borracha : 5 un.
mochila : 3 un. *** ABAIXO DO MÍNIMO ***

ALERTA: repor estoque de: mochila.
====================================================
Ver solução
# Tarefa 1: unidades vendidas e faturamento por produto
relatorio = {}
for t in transacoes:
produto = t["produto"]
if produto not in relatorio:
relatorio[produto] = {"unidades": 0, "faturamento": 0.0}
relatorio[produto]["unidades"] += t["quantidade"]
relatorio[produto]["faturamento"] += t["quantidade"] * t["preco"]

# Tarefa 2: produto mais vendido e de maior faturamento
mais_vendido = None
maior_unidades = 0
maior_fat_nome = None
maior_fat = 0.0

for produto, dados in relatorio.items():
if dados["unidades"] > maior_unidades:
maior_unidades = dados["unidades"]
mais_vendido = produto
if dados["faturamento"] > maior_fat:
maior_fat = dados["faturamento"]
maior_fat_nome = produto

# Tarefa 3: estoque restante e alertas de mínimo
ESTOQUE_MINIMO = 5
estoque_restante = {}
abaixo_minimo = []

for produto, inicial in estoque_inicial.items():
vendidas = relatorio.get(produto, {}).get("unidades", 0)
restante = inicial - vendidas
estoque_restante[produto] = restante
if restante < ESTOQUE_MINIMO:
abaixo_minimo.append(produto)

# Tarefa 4: relatório formatado
print("=" * 52)
print("RELATÓRIO DE VENDAS")
print("=" * 52)
print(f"{'Produto':<12} | {'Unidades':>8} | {'Faturamento':>12}")
print("-" * 52)
for produto, dados in relatorio.items():
print(f"{produto:<12} | {dados['unidades']:>8} | R$ {dados['faturamento']:>9.2f}")
print("-" * 52)
print(f"\nMais vendido (unidades) : {mais_vendido} ({maior_unidades} un.)")
print(f"Maior faturamento : {maior_fat_nome} (R$ {maior_fat:.2f})")

print("\nEstoque restante:")
for produto, qtd in estoque_restante.items():
alerta = " *** ABAIXO DO MÍNIMO ***" if produto in abaixo_minimo else ""
print(f" {produto:<12}: {qtd:>3} un.{alerta}")

if abaixo_minimo:
print(f"\nALERTA: repor estoque de: {', '.join(abaixo_minimo)}.")
print("=" * 52)

Resumo da Aula

Nesta aula, você aprendeu:

  • Dicionários armazenam pares chave-valor; as chaves são únicas e descritivas
  • Valores são acessados por chave (dic["chave"]) ou com .get() para acesso seguro
  • .keys(), .values() e .items() permitem diferentes formas de iteração
  • .update() mescla dicionários; del e .pop() removem pares
  • Use lista para sequências homogêneas; use dicionário para registros com atributos nomeados

Próxima aula: Tuplas e Conjuntos — outras estruturas de dados do Python com propriedades distintas


Referências

Leitura Essencial

  • Python Software Foundation. Mapping Types — dict. Documentação oficial do Python. Disponível em: docs.python.org/3/library/stdtypes.html#mapping-types-dict
    • Referência completa de todos os métodos e comportamentos de dicionários.
  • Forbellone, A. L. V.; Eberspächer, H. F. Lógica de Programação: A Construção de Algoritmos e Estruturas de Dados. 3ª ed. São Paulo: Pearson, 2005.
    • Base conceitual para estruturas de dados associativas.

Aprofundamento (Opcional)