Neste guia, você explorará o uso do `defaultdict`, um recurso do módulo `collections` do Python, projetado para aprimorar o tratamento de `KeyError`s ao manipular dicionários.
Em Python, dicionários são estruturas de dados versáteis, ideais para armazenar informações em pares de chave-valor. O acesso aos valores é feito utilizando as respectivas chaves.
Entretanto, em projetos Python que envolvem múltiplas modificações de dicionários durante a execução, é comum deparar-se com `KeyError`s. Existem diversas estratégias para lidar com esses erros.
Neste tutorial, você irá aprender sobre:
- A natureza dos `KeyError`s e suas causas
- Estratégias para gerenciar `KeyError`s
- O uso do `defaultdict`, uma subclasse que herda as propriedades do dicionário, para gerenciar chaves ausentes de maneira eficaz
Vamos começar!
O Que São `KeyError`s em Python?
Ao definir dicionários em Python, atente-se para:
- A singularidade das chaves: elas não podem se repetir.
- A preferência por coleções imutáveis, como tuplas, ao usar iteráveis como chaves.
Uma chave só é válida se estiver presente no dicionário; caso contrário, ocorre um `KeyError`.
Considere o dicionário `livros_autores`, onde as chaves são títulos de livros e os valores, os nomes dos autores.
Experimente o código em um ambiente Python REPL para acompanhar o tutorial.
livros_autores = {
'Trabalho Focado':'Cal Newport',
'Hiperfoco':'Chris Bailey',
'Giro':'Jenny Blake',
'A Equação da Felicidade':'Neil Pasricha'
}
Acesse o nome do autor utilizando o título do livro como chave:
livros_autores['Hiperfoco'] 'Chris Bailey'
Para obter todos os pares chave-valor, utilize o método `items()`:
for livro, autor in livros_autores.items():
print(f"'{livro}' por {autor}")
'Trabalho Focado' por Cal Newport 'Hiperfoco' por Chris Bailey 'Giro' por Jenny Blake 'A Equação da Felicidade' por Neil Pasricha
Se você tentar acessar um valor usando uma chave inexistente, o Python gera um `KeyError`. Isso ocorre ao tentar acessar os valores de chaves inexistentes, como ‘Garra’ e ‘chave-inexistente’.
livros_autores['Garra']
Traceback (most recent call last): File "", line 1, in KeyError: 'Garra'
livros_autores['chave-inexistente']
Traceback (most recent call last): File "", line 1, in KeyError: 'chave-inexistente'
Como, então, podemos lidar com `KeyError`s em Python?
A seguir, exploraremos algumas estratégias.
Como Gerenciar `KeyError`s em Python

Vamos explorar as abordagens para tratar `KeyError`s usando:
- Instruções condicionais `if-else`
- Blocos `try-except`
- O método `.get()` de dicionários
#1. Usando Instruções Condicionais `If-Else`
Uma forma simples de gerenciar `KeyError`s é utilizando as estruturas condicionais `if-else`.
Em Python, a sintaxe geral de `if-else` é:
if condição:
# execute este bloco
else:
# execute este outro bloco
- Se `condição` for `True`, as instruções dentro do bloco `if` são executadas.
- Caso contrário, as instruções no bloco `else` são executadas.
Aqui, a condição é verificar a existência da chave no dicionário. Se a chave existir, o operador `in` retorna `True` e o valor correspondente é impresso.
chave = 'A Equação da Felicidade'
if chave in livros_autores:
print(livros_autores[chave])
else:
print('Desculpe, esta chave não existe!')
# Saída
# Neil Pasricha
Se a chave não estiver presente, `in` retorna `False`, e o bloco `else` é executado, imprimindo uma mensagem de aviso.
chave = 'chave-inexistente'
if chave in livros_autores:
print(livros_autores[chave])
else:
print('Desculpe, esta chave não existe!')
# Saída
# Desculpe, esta chave não existe!
#2. Usando Instruções `Try-Except`

Outra abordagem comum para o tratamento de `KeyError`s é o uso de blocos `try-except`.
Observe o seguinte trecho de código:
chave = 'chave-inexistente'
try:
print(livros_autores[chave])
except KeyError:
print('Desculpe, esta chave não existe!')
- O bloco `try` tenta acessar o valor associado à chave.
- Se a chave não existir, um `KeyError` é gerado e tratado dentro do bloco `except`.
#3. Usando o Método `.get()`
O método `.get()` embutido em dicionários é uma ferramenta útil para lidar com chaves faltantes.
A sintaxe é: `dicionario.get(chave, valor_padrao)`, onde `dicionario` é um objeto dicionário válido.
– Se a `chave` estiver presente, o método retorna o valor correspondente.
– Caso contrário, retorna `valor_padrao`.
Neste exemplo, `chaves` é uma lista de chaves que queremos acessar. Iteramos sobre essa lista para obter os valores do dicionário `livros_autores`.
Usamos `.get()` com ‘Não existe’ como valor padrão.
chaves = ['Garra', 'Hiperfoco', 'Faça Tempo', 'Trabalho Focado']
for chave in chaves:
print(livros_autores.get(chave, 'Não existe'))
No código acima:
- Para chaves existentes em `livros_autores`, o método `.get()` retorna os valores associados.
- Quando as chaves não existem, como ‘Garra’ e ‘Faça Tempo’, `.get()` retorna o valor padrão ‘Não existe’.
# Saída Não existe Chris Bailey Não existe Cal Newport
Todos os métodos acima tratam erros de chave. No entanto, são detalhados e exigem tratamento explícito de chaves ausentes. O uso de um `defaultdict` pode simplificar esse processo.
`Defaultdict` em Python

O `defaultdict` é uma subclasse do tipo `dict`, herdando seu comportamento, mas com tratamento nativo para chaves ausentes.
É um tipo de dado de contêiner encontrado no módulo `collections` da biblioteca padrão do Python.
É preciso importá-lo:
from collections import defaultdict
A sintaxe geral para usar `defaultdict` é:
defaultdict(função_padrão)
É possível especificar funções como `int`, `float` ou `list` como o atributo `função_padrão`. Se não for fornecido, o padrão é `None`.
Quando uma chave não é encontrada, o método `__missing__()` é acionado, inferindo o valor padrão de `função_padrão` e o retornando.
Em resumo:
- Um `defaultdict` retorna o valor padrão quando uma chave não existe.
- Ele também adiciona o par chave-valor padrão ao dicionário, o qual pode ser modificado.
Exemplos de `Defaultdict` em Python

A seguir, vamos codificar exemplos para entender o funcionamento do `defaultdict`.
`Defaultdict` com Valor Inteiro Padrão
Primeiro, importe `defaultdict`:
from collections import defaultdict import random
Criamos um `defaultdict` para preços:
preços = defaultdict(int)
Preenchemos o dicionário utilizando nomes de frutas como chaves e amostramos aleatoriamente valores de uma lista para obter os preços.
lista_preços = [10, 23, 12, 19, 5]
frutas = ['maçã', 'morango', 'romã', 'mirtilo']
for fruta in frutas:
preços[fruta] = random.choice(lista_preços)
Vejamos os pares chave-valor em `preços`:
print(preços.items())
dict_items([('maçã', 12), ('morango', 10), ('romã', 19), ('mirtilo', 5)])
Assim como um dicionário normal, podemos acessar os valores usando as chaves:
preços['maçã'] # 12
Ao tentar acessar o preço de uma fruta inexistente, como ‘laranja’, ele retorna o valor padrão, zero.
preços['laranja'] # 0
Se imprimirmos o dicionário, veremos que a chave ‘laranja’ foi adicionada com o valor padrão zero.
print(preços.items())
dict_items([('maçã', 12), ('morango', 10), ('romã', 19), ('mirtilo', 5), ('laranja', 0)])
`Defaultdict` com `List` como Valor Padrão
Definimos `alunos_cursos` como um `defaultdict` de listas, onde os nomes dos cursos são as chaves e os valores são listas de alunos matriculados em cada curso.
from collections import defaultdict alunos_cursos = defaultdict(list)
Ao tentar acessar a lista de alunos de ‘Economia’, `defaultdict` retorna uma lista vazia, sem erros de chave!
alunos_cursos['Economia'] # []
Agora, temos uma lista vazia associada ao curso de ‘Economia’, à qual podemos adicionar elementos usando o método `.append()`.
alunos_cursos['Economia'].append('Alex')
Uma entrada foi criada para ‘Economia’ no `defaultdict` `alunos_cursos`.
print(alunos_cursos)
defaultdict(, {'Economia': ['Alex']})
Podemos adicionar mais alunos e criar novos cursos:
alunos_cursos['Economia'].append('Bob')
alunos_cursos['Matemática'].append('Laura')
print(alunos_cursos)
defaultdict(, {'Economia': ['Alex', 'Bob'], 'Matemática': ['Laura']})
Conclusão
Espero que este guia tenha esclarecido o uso do `defaultdict` em Python. Após praticar os exemplos, você pode optar por usar essa estrutura em seus projetos sempre que necessário.
Segue um resumo do que aprendemos neste guia:
- `KeyError`s são comuns ao trabalhar com dicionários.
- Para gerenciar `KeyError`s, utilize métodos como condicionais, blocos `try-except` ou o método `.get()`. O tipo de dados `defaultdict` do módulo `collections` simplifica o tratamento desses erros.
- Use `defaultdict(função_padrão)`, onde `função_padrão` é um objeto callable válido.
- Se uma chave não estiver presente no `defaultdict`, o valor padrão (inferido de `função_padrão`) e a chave são adicionados ao `defaultdict`.
Em seguida, confira o tutorial sobre a função `map` do Python.