Pular para o conteúdo principal

Comprehensions em Python

Introdução

Comprehensions são construções sintáticas poderosas que permitem criar coleções de forma concisa e expressiva. Elas combinam a criação de elementos e sua filtragem em uma única linha de código, tornando o código mais legível e eficiente.

Objetivos de Aprendizado
  • Entender o conceito de comprehensions em Python
  • Dominar list comprehensions para criar listas de forma eficiente
  • Aprender a usar dictionary comprehensions para manipular dicionários
  • Explorar set comprehensions para criar conjuntos sem repetição
  • Compreender generator expressions para processamento eficiente em memória
  • Aplicar comprehensions em problemas práticos

List Comprehensions

List comprehensions permitem criar listas de forma concisa, combinando um loop for com uma expressão.

Sintaxe Básica

# [expressão for item in iterável]
# ou
# [expressão for item in iterável if condição]

Exemplos Simples

# Lista com os quadrados dos números de 0 a 9
quadrados = [x**2 for x in range(10)]
print(quadrados) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# Lista com números pares até 10
pares = [x for x in range(11) if x % 2 == 0]
print(pares) # [0, 2, 4, 6, 8, 10]

# Lista com comprimento de cada palavra
palavras = ["Python", "é", "incrível"]
comprimentos = [len(palavra) for palavra in palavras]
print(comprimentos) # [6, 1, 9]

Com Condições

# Lista com classificação de números
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
classificacao = ["Par" if x % 2 == 0 else "Ímpar" for x in numeros]
print(classificacao) # ['Ímpar', 'Par', 'Ímpar', 'Par', 'Ímpar', 'Par', 'Ímpar', 'Par', 'Ímpar', 'Par']

# Filtrando números primos (simplificado)
def eh_primo(n):
if n <= 1:
return False
if n <= 3:
return True
if n % 2 == 0 or n % 3 == 0:
return False
i = 5
while i * i <= n:
if n % i == 0 or n % (i + 2) == 0:
return False
i += 6
return True

primos = [x for x in range(1, 31) if eh_primo(x)]
print(primos) # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Comprehensions Aninhadas

# Matriz 3x3 usando comprehensions aninhadas
matriz = [[i * 3 + j + 1 for j in range(3)] for i in range(3)]
print(matriz) # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

# Todos os pares (x,y) onde x e y são dígitos
pares_coordenadas = [(x, y) for x in range(10) for y in range(10)]
print(pares_coordenadas[:5]) # [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4)]

# Matriz transposta usando comprehensions
matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transposta = [[linha[i] for linha in matriz] for i in range(3)]
print(transposta) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Quando Usar List Comprehensions

Use list comprehensions quando precisar criar uma nova lista a partir de um iterável existente. Elas são mais eficientes e legíveis do que loops for tradicionais para tarefas simples de transformação ou filtragem.

Dictionary Comprehensions

Dictionary comprehensions permitem criar dicionários de forma concisa, usando uma sintaxe semelhante às list comprehensions.

Sintaxe Básica

# {chave_expressão: valor_expressão for item in iterável}
# ou
# {chave_expressão: valor_expressão for item in iterável if condição}

Exemplos Simples

# Dicionário de número -> quadrado
quadrados = {x: x**2 for x in range(6)}
print(quadrados) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# Dicionário de palavra -> comprimento
palavras = ["Python", "é", "incrível"]
comprimentos = {palavra: len(palavra) for palavra in palavras}
print(comprimentos) # {'Python': 6, 'é': 1, 'incrível': 9}

Transformando Dicionários

# Invertendo um dicionário (chave <-> valor)
pessoas = {"João": 25, "Maria": 30, "José": 35}
pessoas_invertido = {idade: nome for nome, idade in pessoas.items()}
print(pessoas_invertido) # {25: 'João', 30: 'Maria', 35: 'José'}

# Convertendo todas as chaves para maiúsculas
frutas = {"maçã": "vermelha", "banana": "amarela", "uva": "roxa"}
frutas_maiusculas = {k.upper(): v for k, v in frutas.items()}
print(frutas_maiusculas) # {'MAÇÃ': 'vermelha', 'BANANA': 'amarela', 'UVA': 'roxa'}

Com Filtragem

# Filtrando itens caros
produtos = {"notebook": 3500, "celular": 1500, "mouse": 50, "teclado": 100}
itens_caros = {k: v for k, v in produtos.items() if v > 1000}
print(itens_caros) # {'notebook': 3500, 'celular': 1500}

# Selecionando apenas frutas vermelhas
frutas = {"maçã": "vermelha", "banana": "amarela", "morango": "vermelha"}
frutas_vermelhas = {k: v for k, v in frutas.items() if v == "vermelha"}
print(frutas_vermelhas) # {'maçã': 'vermelha', 'morango': 'vermelha'}

Set Comprehensions

Set comprehensions permitem criar conjuntos (sets) de forma concisa, eliminando automaticamente duplicatas.

Sintaxe Básica

# {expressão for item in iterável}
# ou
# {expressão for item in iterável if condição}

Exemplos

# Conjunto de quadrados
quadrados = {x**2 for x in range(10)}
print(quadrados) # {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}

# Extraindo vogais únicas de um texto
texto = "Python é uma linguagem de programação incrível"
vogais = {letra.lower() for letra in texto if letra.lower() in "aeiou"}
print(vogais) # {'a', 'e', 'i', 'o', 'u'}

# Valores únicos de uma lista (removendo duplicatas)
numeros = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unicos = {x for x in numeros}
print(unicos) # {1, 2, 3, 4}

Com Filtragem

# Números pares únicos
numeros = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5]
pares_unicos = {x for x in numeros if x % 2 == 0}
print(pares_unicos) # {2, 4}

# Primeiras letras de cada palavra (únicas)
frase = "o rato roeu a roupa do rei de roma"
iniciais = {palavra[0] for palavra in frase.split()}
print(iniciais) # {'o', 'r', 'a', 'd'}

Generator Expressions

Generator expressions são semelhantes às list comprehensions, mas geram itens sob demanda, economizando memória.

Sintaxe Básica

# (expressão for item in iterável)
# ou
# (expressão for item in iterável if condição)

Comparação com List Comprehension

import sys

# List comprehension (cria toda a lista na memória)
lista = [x for x in range(10000)]

# Generator expression (gera valores sob demanda)
gerador = (x for x in range(10000))

# Comparando o uso de memória
print(f"Tamanho da lista: {sys.getsizeof(lista)} bytes")
print(f"Tamanho do gerador: {sys.getsizeof(gerador)} bytes")

# O gerador só calcula valores quando solicitado
print(next(gerador)) # 0
print(next(gerador)) # 1

Uso Eficiente

# Processando um arquivo grande linha por linha
def ler_arquivo_grande(arquivo):
with open(arquivo, 'r') as f:
return (linha.strip() for linha in f)

# Isso seria mais eficiente que:
# def ler_arquivo_grande(arquivo):
# with open(arquivo, 'r') as f:
# return [linha.strip() for linha in f]

# Somando números grandes sem usar muita memória
soma = sum(x for x in range(10000000))
print(soma) # 49999995000000
Cuidado com a Reutilização

Geradores só podem ser percorridos uma vez. Após esgotar todos os elementos, não é possível reiniciar sem criar um novo gerador.

numeros = (x for x in range(5))
for n in numeros:
print(n, end=" ") # 0 1 2 3 4

print("\nTentando usar novamente:")
for n in numeros:
print(n, end=" ") # Não imprime nada, o gerador já foi esgotado

Casos de Uso Práticos

Processamento de Dados

# Filtrando dados de uma lista de dicionários
alunos = [
{"nome": "João", "nota": 8.5, "aprovado": True},
{"nome": "Maria", "nota": 9.0, "aprovado": True},
{"nome": "Pedro", "nota": 5.5, "aprovado": False},
{"nome": "Ana", "nota": 7.0, "aprovado": True}
]

# Nomes dos alunos aprovados
aprovados = [aluno["nome"] for aluno in alunos if aluno["aprovado"]]
print(aprovados) # ['João', 'Maria', 'Ana']

# Média das notas
media = sum(aluno["nota"] for aluno in alunos) / len(alunos)
print(f"Média: {media:.1f}") # Média: 7.5

# Melhor aluno
melhor_aluno = max(alunos, key=lambda aluno: aluno["nota"])
print(f"Melhor aluno: {melhor_aluno['nome']}") # Melhor aluno: Maria

Transformação de Dados

# Convertendo dados de um formato para outro
dados_csv = [
"id,nome,idade",
"1,João,25",
"2,Maria,30",
"3,Pedro,22"
]

# Converter para lista de dicionários
cabecalho = dados_csv[0].split(',')
registros = [dict(zip(cabecalho, linha.split(','))) for linha in dados_csv[1:]]

print(registros)
# [{'id': '1', 'nome': 'João', 'idade': '25'},
# {'id': '2', 'nome': 'Maria', 'idade': '30'},
# {'id': '3', 'nome': 'Pedro', 'idade': '22'}]

# Converter para outro formato
json_like = {f"pessoa_{r['id']}": {"nome": r["nome"], "idade": int(r["idade"])} for r in registros}
print(json_like)
# {'pessoa_1': {'nome': 'João', 'idade': 25},
# 'pessoa_2': {'nome': 'Maria', 'idade': 30},
# 'pessoa_3': {'nome': 'Pedro', 'idade': 22}}

Criação de Matrizes

# Matriz de identidade 4x4
identidade = [[1 if i == j else 0 for j in range(4)] for i in range(4)]
for linha in identidade:
print(linha)
# [1, 0, 0, 0]
# [0, 1, 0, 0]
# [0, 0, 1, 0]
# [0, 0, 0, 1]

# Criando uma matriz de distância (cada célula contém a distância de Manhattan entre pontos)
pontos = [(i, j) for i in range(3) for j in range(3)]
matriz_distancia = {(p1, p2): abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
for p1 in pontos for p2 in pontos if p1 != p2}

# Exibindo algumas distâncias
print(f"Distância de (0,0) a (2,2): {matriz_distancia[((0,0), (2,2))]}") # 4
print(f"Distância de (1,0) a (0,2): {matriz_distancia[((1,0), (0,2))]}") # 3

Desempenho e Boas Práticas

Desempenho

import time

# Comparando desempenho: loop tradicional vs. comprehension

# Método 1: loop tradicional
def metodo_loop(n):
resultado = []
for i in range(n):
resultado.append(i * i)
return resultado

# Método 2: list comprehension
def metodo_comprehension(n):
return [i * i for i in range(n)]

# Teste de desempenho
n = 1000000

inicio = time.time()
resultado1 = metodo_loop(n)
fim = time.time()
print(f"Loop tradicional: {fim - inicio:.4f} segundos")

inicio = time.time()
resultado2 = metodo_comprehension(n)
fim = time.time()
print(f"List comprehension: {fim - inicio:.4f} segundos")

# List comprehension geralmente é mais rápido

Boas Práticas

# 1. Mantenha as comprehensions simples e legíveis

# Ruim: comprehension complexa e difícil de entender
resultado = [x**2 for x in [y for y in range(10) if y % 2 == 0] if x > 5]

# Melhor: dividir em passos
pares = [y for y in range(10) if y % 2 == 0]
resultado = [x**2 for x in pares if x > 5]

# 2. Use generator expressions para grandes conjuntos de dados

# Ruim para grandes conjuntos: carrega tudo na memória
# sum([x**2 for x in range(10000000)])

# Melhor: processa sob demanda
# sum(x**2 for x in range(10000000))

# 3. Evite efeitos colaterais nas comprehensions

# Ruim: modificando estado externo
total = 0
[total := total + x for x in range(5)] # Não faça isso!

# Melhor: uso funcional
total = sum(x for x in range(5))

Resumo

Nesta aula, você aprendeu sobre:

  • List comprehensions para criar listas de forma concisa e expressiva
  • Dictionary comprehensions para transformar e criar dicionários eficientemente
  • Set comprehensions para criar conjuntos sem duplicatas
  • Generator expressions para processamento eficiente em memória
  • Casos de uso práticos para comprehensions
  • Boas práticas e considerações de desempenho

Próximos Passos

Na próxima aula, exploraremos expressões lambda e funções integradas em Python, que complementam perfeitamente o uso de comprehensions.

Avance para a próxima aula →

← Voltar para Funções