Estruturas de Dados em Python: Guia Completo
Aprenda sobre listas, tuplas, dicionários e conjuntos em Python. Operações, performance e quando usar cada estrutura com exemplos práticos de código.
Dominar as estruturas de dados nativas do Python é essencial para escrever código eficiente e elegante. Neste guia, você vai aprender tudo sobre as quatro estruturas fundamentais — listas, tuplas, dicionários e conjuntos — com exemplos práticos e dicas de performance.
Listas
Listas são a estrutura de dados mais versátil do Python. Elas são ordenadas, mutáveis e permitem elementos duplicados.
Criando listas
# Criando listas de diferentes formas
frutas = ["maçã", "banana", "laranja", "uva"]
numeros = [1, 2, 3, 4, 5]
misturada = [1, "texto", 3.14, True, None]
vazia = []
# Usando o construtor list()
letras = list("Python") # ['P', 'y', 't', 'h', 'o', 'n']
# List comprehension
quadrados = [x ** 2 for x in range(10)]
print(quadrados) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Operações com listas
frutas = ["maçã", "banana", "laranja"]
# Adicionar elementos
frutas.append("uva") # Adiciona no final
frutas.insert(1, "morango") # Adiciona na posição 1
frutas.extend(["kiwi", "manga"]) # Adiciona múltiplos elementos
print(frutas)
# ['maçã', 'morango', 'banana', 'laranja', 'uva', 'kiwi', 'manga']
# Remover elementos
frutas.remove("banana") # Remove pela valor
ultimo = frutas.pop() # Remove e retorna o último
primeiro = frutas.pop(0) # Remove e retorna pela posição
# Buscar e contar
indice = frutas.index("laranja") # Retorna o índice
quantidade = frutas.count("uva") # Conta ocorrências
existe = "kiwi" in frutas # Verifica se existe (True/False)
Fatiamento (Slicing)
numeros = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# lista[início:fim:passo]
print(numeros[2:5]) # [2, 3, 4]
print(numeros[:3]) # [0, 1, 2]
print(numeros[7:]) # [7, 8, 9]
print(numeros[::2]) # [0, 2, 4, 6, 8] (passo 2)
print(numeros[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] (invertido)
# Copiar uma lista (cópia superficial)
copia = numeros[:]
# ou
copia = numeros.copy()
Ordenação
notas = [8.5, 9.2, 7.0, 6.8, 9.8, 7.5]
# Ordenar in-place (modifica a lista original)
notas.sort()
print(notas) # [6.8, 7.0, 7.5, 8.5, 9.2, 9.8]
notas.sort(reverse=True)
print(notas) # [9.8, 9.2, 8.5, 7.5, 7.0, 6.8]
# Ordenar sem modificar (retorna nova lista)
alunos = [
{"nome": "Ana", "nota": 8.5},
{"nome": "Carlos", "nota": 9.2},
{"nome": "Beatriz", "nota": 7.8},
]
ranking = sorted(alunos, key=lambda a: a["nota"], reverse=True)
for i, aluno in enumerate(ranking, 1):
print(f"{i}º lugar: {aluno['nome']} - Nota: {aluno['nota']}")
List Comprehensions avançadas
# Filtrar e transformar
numeros = range(1, 21)
# Números pares elevados ao cubo
pares_cubo = [n ** 3 for n in numeros if n % 2 == 0]
print(pares_cubo) # [8, 64, 216, 512, 1000, ...]
# Comprehension com condição ternária
classificacao = ["par" if n % 2 == 0 else "ímpar" for n in range(1, 6)]
print(classificacao) # ['ímpar', 'par', 'ímpar', 'par', 'ímpar']
# Comprehension aninhada (achatar matriz)
matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
achatada = [num for linha in matriz for num in linha]
print(achatada) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Tuplas
Tuplas são parecidas com listas, mas são imutáveis — uma vez criadas, não podem ser alteradas. Isso as torna mais seguras e um pouco mais rápidas.
# Criando tuplas
coordenadas = (23.5505, -46.6333) # São Paulo
cores_rgb = (255, 128, 0)
singleton = (42,) # Tupla com um elemento (vírgula obrigatória!)
# Desempacotamento
latitude, longitude = coordenadas
print(f"Latitude: {latitude}, Longitude: {longitude}")
# Desempacotamento com *
primeiro, *meio, ultimo = (1, 2, 3, 4, 5)
print(primeiro) # 1
print(meio) # [2, 3, 4]
print(ultimo) # 5
Quando usar tuplas em vez de listas?
# 1. Dados que não devem mudar
MESES = ("Janeiro", "Fevereiro", "Março", "Abril", "Maio",
"Junho", "Julho", "Agosto", "Setembro", "Outubro",
"Novembro", "Dezembro")
# 2. Como chaves de dicionário (listas não podem ser chaves)
localizacoes = {
(-23.55, -46.63): "São Paulo",
(-22.90, -43.17): "Rio de Janeiro",
(-15.78, -47.93): "Brasília",
}
# 3. Retornar múltiplos valores de uma função
def dividir(a, b):
quociente = a // b
resto = a % b
return quociente, resto # Retorna uma tupla
q, r = dividir(17, 5)
print(f"17 ÷ 5 = {q} com resto {r}")
# Named tuples para maior clareza
from collections import namedtuple
Ponto = namedtuple("Ponto", ["x", "y"])
p = Ponto(3, 4)
print(f"Ponto({p.x}, {p.y})")
print(f"Distância da origem: {(p.x**2 + p.y**2)**0.5:.2f}")
Dicionários
Dicionários armazenam pares chave-valor. São incrivelmente rápidos para buscar dados e são uma das estruturas mais utilizadas no dia a dia.
# Criando dicionários
aluno = {
"nome": "Maria Silva",
"idade": 22,
"curso": "Ciência da Computação",
"notas": [8.5, 9.0, 7.5, 8.8],
"ativo": True,
}
# Acessando valores
print(aluno["nome"]) # Maria Silva
print(aluno.get("email", "N/A")) # N/A (valor padrão se não existir)
# Modificando
aluno["idade"] = 23
aluno["email"] = "maria@email.com"
# Removendo
del aluno["ativo"]
curso = aluno.pop("curso") # Remove e retorna o valor
Iteração em dicionários
estoque = {
"notebook": {"preco": 3500, "quantidade": 25},
"mouse": {"preco": 89.90, "quantidade": 150},
"teclado": {"preco": 199.90, "quantidade": 80},
"monitor": {"preco": 1200, "quantidade": 40},
}
# Iterar pelas chaves
for produto in estoque:
print(produto)
# Iterar pelos valores
for info in estoque.values():
print(info)
# Iterar pelos pares chave-valor
for produto, info in estoque.items():
valor_total = info["preco"] * info["quantidade"]
print(f"{produto}: R${valor_total:,.2f} em estoque")
# Dict comprehension
precos = {produto: info["preco"] for produto, info in estoque.items()}
print(precos)
# {'notebook': 3500, 'mouse': 89.9, 'teclado': 199.9, 'monitor': 1200}
# Filtrar por condição
caros = {p: i for p, i in estoque.items() if i["preco"] > 100}
Métodos úteis de dicionários
config_padrao = {
"tema": "claro",
"idioma": "pt-BR",
"notificacoes": True,
"fonte_tamanho": 14,
}
config_usuario = {
"tema": "escuro",
"fonte_tamanho": 16,
}
# Mesclar dicionários
config_final = {**config_padrao, **config_usuario}
print(config_final)
# {'tema': 'escuro', 'idioma': 'pt-BR', 'notificacoes': True, 'fonte_tamanho': 16}
# Python 3.9+: operador merge
config_final = config_padrao | config_usuario
# defaultdict para contagem
from collections import defaultdict, Counter
texto = "banana abacaxi banana maçã laranja banana maçã"
palavras = texto.split()
# Usando Counter
contagem = Counter(palavras)
print(contagem.most_common(3))
# [('banana', 3), ('maçã', 2), ('abacaxi', 1)]
Conjuntos (Sets)
Conjuntos são coleções não ordenadas de elementos únicos. Eles são ótimos para eliminar duplicatas e fazer operações matemáticas de conjuntos.
# Criando conjuntos
frutas = {"maçã", "banana", "laranja", "maçã"} # duplicata ignorada
print(frutas) # {'banana', 'laranja', 'maçã'}
numeros = set([1, 2, 2, 3, 3, 3, 4, 4, 4, 4])
print(numeros) # {1, 2, 3, 4}
# Adicionar e remover
frutas.add("uva")
frutas.discard("banana") # Não dá erro se não existir
Operações de conjuntos
python_devs = {"Ana", "Carlos", "Maria", "João", "Pedro"}
javascript_devs = {"Carlos", "Maria", "Lucas", "Fernanda", "Pedro"}
# União: quem sabe pelo menos uma
todos = python_devs | javascript_devs
# ou: python_devs.union(javascript_devs)
print(f"Total de devs: {len(todos)}")
# Interseção: quem sabe as duas
fullstack = python_devs & javascript_devs
print(f"Fullstack: {fullstack}") # {'Carlos', 'Maria', 'Pedro'}
# Diferença: quem sabe só Python
so_python = python_devs - javascript_devs
print(f"Só Python: {so_python}") # {'Ana', 'João'}
# Diferença simétrica: quem sabe só uma
exclusivos = python_devs ^ javascript_devs
print(f"Exclusivos: {exclusivos}") # {'Ana', 'João', 'Lucas', 'Fernanda'}
Uso prático: eliminando duplicatas
# Remover duplicatas mantendo a ordem
def remover_duplicatas(lista):
vistos = set()
resultado = []
for item in lista:
if item not in vistos:
vistos.add(item)
resultado.append(item)
return resultado
emails = [
"ana@email.com",
"carlos@email.com",
"ana@email.com",
"maria@email.com",
"carlos@email.com",
]
unicos = remover_duplicatas(emails)
print(unicos) # ['ana@email.com', 'carlos@email.com', 'maria@email.com']
Comparação de Performance
A escolha da estrutura de dados impacta diretamente a performance do seu código:
| Operação | Lista | Tupla | Dicionário | Conjunto |
|---|---|---|---|---|
| Acesso por índice | O(1) | O(1) | — | — |
| Busca por valor | O(n) | O(n) | O(1) | O(1) |
| Inserção | O(1)* | — | O(1) | O(1) |
| Remoção | O(n) | — | O(1) | O(1) |
| Memória | Média | Baixa | Alta | Média |
*O(1) para append; O(n) para insert no início.
import time
# Demonstrando a diferença de busca
tamanho = 1_000_000
lista_grande = list(range(tamanho))
conjunto_grande = set(range(tamanho))
# Busca na lista: O(n) - lento
inicio = time.time()
999_999 in lista_grande
tempo_lista = time.time() - inicio
# Busca no conjunto: O(1) - rápido
inicio = time.time()
999_999 in conjunto_grande
tempo_set = time.time() - inicio
print(f"Lista: {tempo_lista:.6f}s")
print(f"Conjunto: {tempo_set:.6f}s")
print(f"Conjunto é {tempo_lista/tempo_set:.0f}x mais rápido!")
Resumo: Quando Usar Cada Uma?
- Lista: Quando precisa de uma coleção ordenada e mutável. Ideal para sequências de dados que podem ser modificados.
- Tupla: Quando os dados não devem mudar. Ideal para coordenadas, retorno de funções, chaves de dicionário.
- Dicionário: Quando precisa associar chaves a valores. Ideal para configurações, mapeamentos, dados estruturados.
- Conjunto: Quando precisa de elementos únicos ou fazer operações de conjuntos. Ideal para eliminar duplicatas e verificar pertinência.
Dominar essas quatro estruturas é fundamental para se tornar um bom programador Python. Pratique com projetos reais e você vai perceber que escolher a estrutura certa faz toda a diferença no seu código!
Equipe Python Brasil
Contribuidor do Python Brasil — Aprenda Python em Português