Tuplas e sets
Você já conhece listas. O Python tem mais dois tipos de coleção que resolvem problemas que as listas não conseguem. Tuplas guardam um grupo fixo de valores que nunca vai mudar. Sets guardam apenas valores únicos e permitem verificar se um item pertence à coleção instantaneamente, não importa o tamanho dela.
Tuplas
Uma tupla é um grupo ordenado de valores que não pode ser alterado depois de criado. Parênteses definem uma tupla, mas eles são opcionais. A vírgula é o que de fato torna algo uma tupla. Uma tupla de um único item exige uma vírgula ao final.
point = (10, 20)
rgb = (255, 128, 0)
dimensions = (1920, 1080)
single = (42,) # vírgula ao final é obrigatória para uma tupla de um único item
also_tuple = 42, 99 # os parênteses são opcionais; a vírgula é o que faz a tuplaAcessar por índice funciona exatamente como em uma lista. Tentar alterar um item gera um TypeError:
point = (10, 20)
point[0] # 10
point[1] # 20
point[-1] # 20
point[0] = 99 # TypeError: 'tuple' object does not support item assignment(42,) precisa daquela vírgula solitária ao final. Tente reatribuir um item e você recebe um TypeError, e essa sensação de "travado" é exatamente o motivo de escolher uma tupla. Quando usar uma tupla
Use uma tupla quando você tiver um pequeno grupo de valores relacionados que pertencem juntos e não vão mudar. Coordenadas (x, y), uma cor (r, g, b), um par nome-pontuação ("Alice", 87). A estrutura fixa sinaliza para quem lê o código que esse grupo é tratado como uma única unidade.
(r, g, b), um par nome-e-pontuação. Como tuplas são hashable, você pode até usar uma como chave de dict. Uma lista não consegue fazer isso, e é isso que confunde as pessoas na primeira vez que tentam. locations = {}
locations[(40, -74)] = "Nova York" # tupla como chave de dict, funciona
locations[[40, -74]] = "Nova York" # lista como chave de dict, TypeErrorDesempacotamento
Desempacotar extrai valores de uma tupla e atribui cada um a seu próprio nome em uma única linha. O número de nomes precisa corresponder ao número de valores. Use * para capturar os itens restantes em uma lista.
x, y = point. O número de nomes precisa corresponder ao número de valores, a menos que você adicione um *rest para recolher o que sobrar. Isso fez sentido pra mim no dia em que parei de escrever point[0] e point[1] em todo lugar. point = (10, 20)
x, y = point
print(x) # 10
print(y) # 20
first, *rest = [1, 2, 3, 4, 5]
# first = 1, rest = [2, 3, 4, 5]
head, *middle, tail = [1, 2, 3, 4, 5]
# head = 1, middle = [2, 3, 4], tail = 5Tuplas nomeadas
Uma tupla nomeada é uma tupla em que cada posição tem um nome. Em vez de lembrar que point[0] é a coordenada x, você escreve point.x. Os valores continuam imutáveis; você só ganha nomes de atributo legíveis em vez de posições numéricas.
point.x em vez de lembrar que point[0] é o x. Ela continua totalmente imutável e se comporta como uma tupla comum em tudo o mais. Seu "eu do futuro" vai agradecer pelos nomes quando reler o código. namedtuple faz parte da biblioteca padrão, então precisa de um import antes: from collections import namedtuple. Imports recebem um tratamento completo no capítulo de Módulos.
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
Player = namedtuple("Player", ["name", "score", "level"])
p = Point(10, 20)
p.x # 10
p.y # 20
alice = Player("Alice", 87, 5)
alice.name # "Alice"
alice.score # 87Sets
Um set é uma coleção de valores únicos sem ordem garantida. Adicionar o mesmo valor duas vezes não faz nada: um set mantém apenas uma cópia de cada item. Use chaves para um set com itens, ou set() para criar um set vazio.
set() para um vazio, porque {} é secretamente um dict vazio. Esse último detalhe pega quase todo mundo. tags = {"python", "beginner", "tutorial"}
numbers = {1, 2, 3, 4, 5}
empty = set() # NÃO {} (isso é um dict vazio)Adicionar o mesmo valor duas vezes não altera o set:
tags.add("python") # tags permanece igual, "python" já estava presenteQuando usar um set
Sets são a ferramenta certa para três coisas: remover duplicatas de uma lista, checar rapidamente se algo está em uma coleção grande, e comparar dois grupos para descobrir o que eles têm em comum ou de diferente.
# Remove duplicatas de uma lista
raw = ["cat", "dog", "cat", "bird", "dog", "cat"]
unique = list(set(raw)) # ["cat", "dog", "bird"] (ordem não garantida)# Verificação rápida de pertencimento
valid_codes = {"USD", "EUR", "GBP", "JPY"}
code = "EUR"
if code in valid_codes: # busca instantânea, mesmo com milhares de códigos
print("Valid")Operações de conjunto
Sets suportam as mesmas operações que você aprendeu em matemática: união (tudo que está em qualquer um dos dois sets), interseção (só o que os dois têm em comum) e diferença (o que um tem e o outro não). O Python usa símbolos de operador para isso, e cada um tem um método equivalente.
| é união (em qualquer um dos dois), & é interseção (nos dois), - é diferença (em um mas não no outro), e ^ é diferença simétrica (em um mas não nos dois). Cada uma também tem um método por extenso, como .union(), se você preferir palavras a símbolos. a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
a | b # {1, 2, 3, 4, 5, 6} (união: tudo em qualquer um dos dois)
a & b # {3, 4} (interseção: só nos dois)
a - b # {1, 2} (diferença: em a mas não em b)
b - a # {5, 6} (diferença no outro sentido)
a ^ b # {1, 2, 5, 6} (diferença simétrica: em um mas não nos dois)Elas também têm formas de método: .union(), .intersection(), .difference(), .symmetric_difference().
Modificando sets
Sets são mutáveis. .add() adiciona um item. .update() adiciona vários de uma vez a partir de qualquer lista ou outro iterável. .remove() apaga um item, mas gera um erro se ele não estiver lá. .discard() apaga silenciosamente se o item existir e não faz nada se não existir.
.add() coloca um item, .update() adiciona um lote inteiro a partir de uma lista ou outro iterável. O par para não confundir é a remoção: .remove() dá erro se o item não estiver lá, enquanto .discard() dá de ombros e segue em frente. Quando você não tem certeza se o item está no set, .discard() te poupa de um erro desnecessário. tags = {"python", "beginner"}
tags.add("tutorial") # adiciona um item
tags.update(["web", "api"]) # adiciona múltiplos itens de qualquer iterável
tags.remove("beginner") # remove, gera KeyError se não encontrar
tags.discard("missing") # remove, sem erro se não encontrar
tags.pop() # remove e retorna um item arbitrário
tags.clear() # remove tudoUse .discard() quando não tiver certeza se o item existe.
Frozen sets
Um frozen set é um set que você não pode modificar depois de criado. O principal motivo para usar um: frozen sets são hashable, então podem ser usados como chaves de dicionário ou armazenados dentro de outros sets.
valid_statuses = frozenset({"active", "paused", "deleted"})
valid_statuses.add("archived") # AttributeError, frozenset é imutávelEscolhendo a coleção certa
Quatro tipos, cada um com um papel claro. Pergunte o que você precisa fazer com os dados, e a escolha certa geralmente aparece.
| list | tuple | set | dict | |
|---|---|---|---|---|
| Ordenado | Sim | Sim | Não | Sim (ordem de inserção) |
| Mutável | Sim | Não | Sim | Sim |
| Duplicatas | Sim | Sim | Não | Não (chaves) |
| Acesso por | Índice | Índice | n/a | Chave |
| Use quando | Sequência ordenada e alterável | Registro fixo | Valores únicos, pertencimento rápido | Busca por chave-valor |
Uma regra rápida de decisão:
- Precisa buscar algo pelo nome? → dict
- Precisa de uma coleção ordenada que você vai modificar? → list
- Tem um grupo fixo de valores relacionados? → tuple
- Precisa de valores únicos ou testes de pertencimento rápidos? → set
Na prática
Usando tuplas para armazenar registros fixos e um set para acompanhar valores únicos:
home = (51.5074, -0.1278) # latitude, longitude
office = (51.5155, -0.0922)
home_lat, home_lon = home
print(f"Home: {home_lat}, {home_lon}")
# Acompanha visitantes únicos com um set
visitors = set()
visitors.add("alice")
visitors.add("bob")
visitors.add("alice") # já está no set, ignorado silenciosamente
visitors.add("carol")
print(f"Unique visitors: {len(visitors)}")
print(f"alice visited: {'alice' in visitors}")
print(f"dave visited: {'dave' in visitors}")
