Dicionários
Listas permitem que você procure algo pela posição. Mas muitas vezes você quer procurar algo pelo nome. Não "me dê o item 3", mas "me dê a pontuação da Alice". Um dicionário guarda dados em pares de chave-valor: você busca um valor pela sua chave, não pela sua posição.
Criando um dicionário
Chaves (as chaves de curva, {}) com dois-pontos entre cada chave e valor, e vírgulas entre os pares. As chaves quase sempre são strings. Os valores podem ser qualquer coisa: números, strings, outras listas, até outros dicionários.
player = {
"name": "Alice",
"score": 87,
"level": 5,
"alive": True,
}Acessando valores
Use colchetes com a chave para obter o valor. Se a chave não existir, o Python lança um KeyError. Use .get() quando você não tiver certeza se a chave está lá: ele retorna None em vez de travar, ou um valor padrão que você especificar.
player = {"name": "Alice", "score": 87}
player["name"] # "Alice"
player["score"] # 87
player["lives"] # KeyError (a chave não existe)player.get("score") # 87
player.get("lives") # None (sem erro, retorna None por padrão)
player.get("lives", 3) # 3 (usa esse padrão se a chave não existir).get() é mais seguro sempre que uma chave pode estar ausente:
count = inventory.get("arrows", 0) # 0 se "arrows" não estiver no dictd["key"] te entrega o valor, mas lança KeyError se essa chave não existir. Quando você não tem certeza, use .get(): ele retorna None em vez de travar, ou um padrão que você passar. Hoje eu coloco padrão em tudo, e meus programas pararam de travar por chaves ausentes. Adicionando e atualizando
Atribua a uma chave usando colchetes. Se a chave já existir, o valor é substituído. Se ainda não existir, uma nova entrada é criada. Use .update() para mesclar um dicionário inteiro de uma vez.
player = {"name": "Alice", "score": 87}
player["score"] = 92 # atualiza um valor existente
player["level"] = 5 # adiciona uma nova chaveextras = {"level": 5, "alive": True}
player.update(extras) # adiciona/sobrescreve com as chaves de extras.update() para incorporar um dicionário inteiro de uma vez. Removendo itens
Quatro formas de remover entradas. .pop() remove uma chave e devolve o valor. .pop() com um padrão é seguro quando a chave pode não existir. del remove uma chave sem retornar nada. .clear() esvazia o dicionário inteiro.
player = {"name": "Alice", "score": 87, "level": 5}
player.pop("level") # remove "level" e retorna 5
player.pop("lives", None) # pop seguro, retorna None se a chave não existir
del player["score"] # remove "score", sem valor de retorno
player.clear() # remove tudo.pop() com um padrão é a forma mais segura de remover uma chave que pode não existir.
.pop(key) remove uma chave e te devolve o valor, e .pop(key, None) fica tranquilo quando a chave pode não estar lá. del d[key] remove sem retornar nada, .clear() esvazia tudo. O padrão no .pop() me salvou de muitos sustos com KeyError. Iterando
Três visões permitem percorrer diferentes partes de um dicionário. Iterar o dict diretamente te dá as chaves. .values() dá os valores. .items() dá os dois ao mesmo tempo e é o que você vai usar mais: descompacte cada par em dois nomes para loops limpos e legíveis.
player = {"name": "Alice", "score": 87, "level": 5}
for key in player: # itera as chaves (o mais comum)
print(key)
for key in player.keys(): # o mesmo, view explícita de chaves
print(key)
for value in player.values(): # os valores
print(value)
for key, value in player.items(): # os dois, o mais útil
print(f"{key}: {value}").items() é o que você vai usar mais. Descompactar cada par em dois nomes torna o loop legível.
.values() dá os valores, e .items() dá os dois ao mesmo tempo, que é o que você vai usar mais. Descompactar cada par em dois nomes, como em for key, value in player.items(), deixou meus loops muito mais fáceis de ler. Verificando pertencimento
in verifica se uma chave existe no dicionário. Ele não verifica valores, só chaves. Para verificar se algo não está presente, use not in.
player = {"name": "Alice", "score": 87}
"name" in player # True
"lives" in player # False
"lives" not in player # Truein verifica apenas as chaves. Para verificar valores, use in player.values(), embora isso raramente seja necessário.
in te diz se uma chave está no dict, e só uma chave, nunca um valor. Continua rápido não importa o tamanho do dict. Inverta para not in para verificar que algo está ausente. Dicionários aninhados
Valores podem ser dicionários eles mesmos. É assim que você representa dados estruturados em múltiplos níveis: um jogador que tem uma seção de estatísticas, um arquivo de configuração com subsseções. Dois conjuntos de colchetes acessam um valor aninhado: o primeiro escolhe a chave externa, o segundo escolhe a chave interna.
users = {
"alice": {"score": 87, "level": 5},
"bob": {"score": 74, "level": 3},
}
users["alice"]["score"] # 87
users["bob"]["level"] # 3O acesso é feito com colchetes encadeados. Para estruturas profundamente aninhadas, isso pode ficar difícil de gerenciar, então mantenha o aninhamento raso sempre que puder.
setdefault
.setdefault() lê uma chave se ela existir, ou a define com um valor padrão se não existir, e então retorna o valor. É útil quando você precisa que uma chave exista, mas não quer sobrescrevê-la se ela já estiver lá.
inventory = {}
inventory.setdefault("arrows", 0) # define "arrows": 0, retorna 0
inventory.setdefault("arrows", 10) # "arrows" já existe, sem mudança, retorna 0É útil para construir estruturas agrupadas sem verificar antes se a chave existe:
groups = {}
for name, team in players:
groups.setdefault(team, []).append(name).setdefault(key, default) lê uma chave se ela estiver lá, ou a define com o padrão e retorna se não estiver. É a forma organizada de garantir que uma chave existe sem atropelar um valor que já está lá. Uso mais para agrupar coisas, sem precisar checar "essa chave já existe?". collections.defaultdict e Counter
A biblioteca padrão tem duas subclasses de dict que resolvem padrões comuns automaticamente. defaultdict cria um valor padrão para chaves ausentes, então você nunca recebe um KeyError. Counter conta quantas vezes cada item aparece em uma sequência e devolve o resultado como um dict.
defaultdict e Counter ficam na biblioteca padrão, então precisam ser importados antes de usar. Imports recebem o tratamento completo no capítulo de Módulos.
from collections import defaultdict
groups = defaultdict(list)
for name, team in players:
groups[team].append(name) # sem KeyError se team for novofrom collections import Counter
words = ["cat", "dog", "cat", "bird", "cat", "dog"]
counts = Counter(words)
# Counter({'cat': 3, 'dog': 2, 'bird': 1})
counts.most_common(2) # [('cat', 3), ('dog', 2)]Counter economiza muito código repetitivo de "contar coisas em um loop".
defaultdict preenche um padrão para qualquer chave ausente, então agrupar e contar param de te jogar um KeyError na cara. Counter contabiliza quantas vezes cada item aparece em uma sequência e devolve tudo como um dict. Da primeira vez que troquei um loop de contagem escrito à mão por Counter, metade do meu código desapareceu. Na prática
Construindo um rastreador de pontuações e imprimindo um resumo com todas as entradas:
scores = {"Alice": 87, "Bob": 74, "Carol": 92, "Dave": 55}
total = sum(scores.values())
average = total / len(scores)
print(f"Jogadores: {len(scores)}")
print(f"Média: {average:.1f}")
print(f"Maior: {max(scores.values())}")
print(f"Menor: {min(scores.values())}")
print()
for name, score in scores.items():
print(f" {name}: {score}")
