#6 - Sets e Dicionários

Como criar e manipular sets e dicionários em Python, incluindo frozenset, dicionários aninhados e os principais métodos de cada estrutura.

Imagem de capa

Fechando o bloco de estruturas de dados nativas do Python, esse post cobre sets e dicionários. São duas estruturas bem diferentes entre si — set é uma coleção sem ordem definida e sem duplicados, dicionário guarda pares chave-valor — mas ambas extremamente úteis no dia a dia.

Sets

Um set é uma coleção não-ordenada e sem itens duplicados, criada com chaves {}:

frutas = {"maçã", "banana", "laranja"}
print(frutas)
print(type(frutas))
{'banana', 'maçã', 'laranja'}
<class 'set'>

Repare que a ordem de exibição não necessariamente é a mesma ordem em que os itens foram inseridos — sets não garantem ordem. E se você tentar colocar um valor duplicado, ele simplesmente é ignorado:

numeros = {1, 2, 3, 2, 1}
print(numeros)
{1, 2, 3}

Nota: pra criar um set vazio, use set(), e não {}{} sozinho cria um dicionário vazio, não um set.

Acessando itens

Como sets não têm índice (afinal, não há ordem garantida), não dá pra acessar um item pela posição como em listas. O jeito de verificar se um valor está presente é com in, e pra percorrer todos os itens, um loop:

frutas = {"maçã", "banana", "laranja"}

print("banana" in frutas)

for fruta in frutas:
    print(fruta)
True
maçã
banana
laranja

Adicionando itens

frutas = {"maçã", "banana"}

frutas.add("laranja")                  # adiciona um item
print(frutas)

frutas.update(["uva", "manga"])        # adiciona vários itens de uma vez
print(frutas)
{'maçã', 'banana', 'laranja'}
{'maçã', 'banana', 'laranja', 'uva', 'manga'}

Removendo itens

frutas = {"maçã", "banana", "laranja"}

frutas.remove("banana")   # lança erro se o item não existir
print(frutas)

frutas.discard("uva")     # não lança erro se o item não existir
print(frutas)

item = frutas.pop()        # remove um item arbitrário (sets não têm ordem)
print(item, frutas)

frutas.clear()             # esvazia o set
print(frutas)
{'maçã', 'laranja'}
{'maçã', 'laranja'}
laranja {'maçã'}
set()

Juntando sets

Além de update(), sets têm operações inspiradas direto na matemática de conjuntos:

a = {1, 2, 3}
b = {3, 4, 5}

print(a.union(b))          # união: todos os itens dos dois
print(a.intersection(b))   # interseção: só o que está nos dois
print(a.difference(b))     # diferença: o que está em a mas não em b
{1, 2, 3, 4, 5}
{3}
{1, 2}

frozenset

frozenset é a versão imutável de um set — depois de criado, não dá pra adicionar ou remover itens. É útil, por exemplo, quando você precisa de um conjunto que sirva como chave de dicionário (sets normais não podem ser chave, porque são mutáveis):

cores = frozenset(["vermelho", "verde", "azul"])
print(cores)

cores.add("amarelo")
frozenset({'vermelho', 'verde', 'azul'})
AttributeError: 'frozenset' object has no attribute 'add'

Principais métodos de set

Método O que faz
add(x) Adiciona um item
update(iteravel) Adiciona vários itens
remove(x) Remove x (erro se não existir)
discard(x) Remove x (sem erro se não existir)
union(outro) Retorna a união com outro set
intersection(outro) Retorna a interseção com outro set
difference(outro) Retorna a diferença com outro set
clear() Remove todos os itens

Dicionários

Um dicionário guarda dados em pares chave-valor, criado com chaves {} no formato chave: valor. É provavelmente a estrutura de dados mais usada em Python depois das listas:

pessoa = {
    "nome": "Felipe",
    "idade": 30,
    "cidade": "São Paulo"
}

print(pessoa)
print(type(pessoa))
{'nome': 'Felipe', 'idade': 30, 'cidade': 'São Paulo'}
<class 'dict'>

Nota: desde o Python 3.7, dicionários mantêm a ordem de inserção dos itens — diferente de sets, que não garantem ordem nenhuma.

Acessando itens

O acesso é feito pela chave, entre colchetes, ou pelo método .get() (que é mais seguro, porque não lança erro se a chave não existir):

pessoa = {"nome": "Felipe", "idade": 30}

print(pessoa["nome"])
print(pessoa.get("idade"))
print(pessoa.get("profissao"))            # chave inexistente: retorna None
print(pessoa.get("profissao", "não informado"))  # com valor padrão
Felipe
30
None
não informado

Alterando itens

pessoa = {"nome": "Felipe", "idade": 30}
pessoa["idade"] = 31
print(pessoa)

pessoa.update({"idade": 32, "cidade": "São Paulo"})
print(pessoa)
{'nome': 'Felipe', 'idade': 31}
{'nome': 'Felipe', 'idade': 32, 'cidade': 'São Paulo'}

Adicionando itens

Adicionar um item novo é igual a alterar um existente: se a chave não existe ainda, o Python cria ela:

pessoa = {"nome": "Felipe"}
pessoa["profissao"] = "Desenvolvedor"
print(pessoa)
{'nome': 'Felipe', 'profissao': 'Desenvolvedor'}

Removendo itens

pessoa = {"nome": "Felipe", "idade": 30, "cidade": "São Paulo"}

pessoa.pop("idade")           # remove pela chave e retorna o valor
print(pessoa)

del pessoa["cidade"]           # remove pela chave
print(pessoa)

pessoa.clear()                 # esvazia o dicionário
print(pessoa)
{'nome': 'Felipe', 'cidade': 'São Paulo'}
{'nome': 'Felipe'}
{}

Percorrendo dicionários com loop

pessoa = {"nome": "Felipe", "idade": 30, "cidade": "São Paulo"}

for chave in pessoa:                 # por padrão, itera sobre as chaves
    print(chave)

for valor in pessoa.values():        # itera sobre os valores
    print(valor)

for chave, valor in pessoa.items():  # itera sobre chave e valor juntos
    print(chave, "->", valor)
nome
idade
cidade
Felipe
30
São Paulo
nome -> Felipe
idade -> 30
cidade -> São Paulo

Copiando dicionários

Assim como listas, atribuir dict2 = dict1 não cria uma cópia — cria só uma segunda referência pro mesmo dicionário. Pra copiar de verdade, use .copy():

original = {"nome": "Felipe"}
copia_errada = original
copia_errada["nome"] = "Outro nome"
print(original)   # também mudou!

original = {"nome": "Felipe"}
copia = original.copy()
copia["nome"] = "Outro nome"
print(original)   # não mudou
print(copia)
{'nome': 'Outro nome'}
{'nome': 'Felipe'}
{'nome': 'Outro nome'}

Dicionários aninhados

Um dicionário pode ter outro dicionário como valor — isso é bem comum quando você está modelando dados mais complexos, como um registro com sub-registros:

familia = {
    "filho1": {"nome": "Emília", "idade": 8},
    "filho2": {"nome": "Tobias", "idade": 5}
}

print(familia["filho2"]["nome"])
Tobias

Percorrer um dicionário aninhado normalmente exige um loop dentro de outro:

for filho, dados in familia.items():
    print(filho)
    for chave, valor in dados.items():
        print(f"  {chave}: {valor}")
filho1
  nome: Emília
  idade: 8
filho2
  nome: Tobias
  idade: 5

Principais métodos de dicionário

Método O que faz
get(chave, padrao) Retorna o valor da chave (ou o padrão, se não existir)
keys() Retorna todas as chaves
values() Retorna todos os valores
items() Retorna pares (chave, valor)
update(outro_dict) Mescla outro dicionário no atual
pop(chave) Remove a chave e retorna o valor
clear() Remove todos os itens

E com isso você fecha o quarteto de estruturas de dados nativas mais usadas em Python: listas, tuplas, sets e dicionários. No próximo post da série, a gente entra nas estruturas condicionais — if, elif, else e companhia.

Fonte adaptada: Python Sets, Python - Access Set Items, Python - Add Set Items, Python - Remove Set Items, Python - Loop Sets, Python - Join Sets, Python - Frozenset, Python Set Methods, Python Dictionaries, Python - Access Dictionary Items, Python - Change Dictionary Items, Python - Add Dictionary Items, Python - Remove Dictionary Items, Python - Loop Dictionaries, Python - Copy Dictionaries, Python - Nested Dictionaries, Python Dictionary Methods