List comprehensions: sintaxe e casos de uso
1. Introdução às List Comprehensions
List comprehensions são uma construção sintática poderosa do Python que permite criar listas de forma concisa e expressiva. Elas surgiram como uma alternativa elegante aos loops for tradicionais, inspiradas pela notação de conjuntos da matemática ({x² | x ∈ ℕ}).
A sintaxe básica é surpreendentemente simples:
[expressão for item in iterável]
Para entender o valor das list comprehensions, compare estas duas abordagens equivalentes:
Loop tradicional:
quadrados = []
for x in range(10):
quadrados.append(x ** 2)
List comprehension:
quadrados = [x ** 2 for x in range(10)]
A versão com comprehension é mais curta, mais legível e mais pythonica. Em vez de três linhas com construção explícita da lista, temos uma única linha que declara claramente a intenção: "crie uma lista com x² para cada x no intervalo de 0 a 9".
2. Estrutura Fundamental da Sintaxe
Toda list comprehension possui três componentes obrigatórios:
- Expressão de saída: o valor que será incluído na lista (pode ser qualquer expressão Python)
- Variável de iteração: o nome que receberá cada elemento do iterável
- Iterável fonte: a sequência sobre a qual iteramos
A ordem de avaliação ocorre da direita para a esquerda: primeiro o for itera sobre o iterável, depois a expressão é avaliada para cada elemento.
Exemplos simples:
# Quadrados perfeitos
quadrados = [n ** 2 for n in range(1, 6)]
print(quadrados) # [1, 4, 9, 16, 25]
# Extrair vogais de uma string
frase = "Python é incrível"
vogais = [letra for letra in frase if letra.lower() in 'aeiou']
print(vogais) # ['o', 'é', 'i', 'í', 'e']
3. Filtragem com Condicionais (if)
O poder das list comprehensions se expande significativamente com a adição de filtros condicionais. A sintaxe é:
[expressão for item in iterável if condição]
Casos práticos:
# Números pares até 20
pares = [x for x in range(21) if x % 2 == 0]
print(pares) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# Strings com mais de 5 caracteres
nomes = ["Ana", "Fernanda", "João", "Sebastião", "Lu"]
nomes_longos = [nome for nome in nomes if len(nome) > 5]
print(nomes_longos) # ['Fernanda', 'Sebastião']
Diferença crucial: O if no final da comprehension filtra elementos do iterável. Já um if-else dentro da expressão de saída transforma cada elemento:
# if como filtro (remove ímpares)
pares_filtrados = [x for x in range(10) if x % 2 == 0]
# if-else como transformação (classifica todos)
classificacao = ["par" if x % 2 == 0 else "ímpar" for x in range(10)]
4. Aninhamento de Loops em Comprehensions
List comprehensions suportam múltiplos loops aninhados, equivalentes a loops for aninhados tradicionais:
[expressão for a in A for b in B]
Exemplos práticos:
# Produto cartesiano de duas listas
cores = ["vermelho", "azul"]
tamanhos = ["P", "M", "G"]
combinacoes = [(cor, tam) for cor in cores for tam in tamanhos]
print(combinacoes)
# [('vermelho', 'P'), ('vermelho', 'M'), ('vermelho', 'G'),
# ('azul', 'P'), ('azul', 'M'), ('azul', 'G')]
# Achatar uma matriz (lista de listas)
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]
A ordem dos for na comprehension segue exatamente a mesma ordem dos loops aninhados tradicionais — primeiro o loop mais externo, depois o interno.
5. Uso Avançado com Expressões Complexas
A expressão de saída pode conter chamadas de funções, métodos e construções mais elaboradas:
# Aplicar função a cada elemento
def celsius_para_fahrenheit(c):
return (c * 9/5) + 32
temperaturas_c = [0, 20, 30, 40]
temperaturas_f = [celsius_para_fahrenheit(c) for c in temperaturas_c]
print(temperaturas_f) # [32.0, 68.0, 86.0, 104.0]
# Chamada de métodos encadeados
sujos = [" hello ", "WORLD ", " python "]
limpos = [s.strip().upper() for s in sujos]
print(limpos) # ['HELLO', 'WORLD', 'PYTHON']
# Combinando com enumerate() e zip()
nomes = ["Alice", "Bob", "Carol"]
idades = [25, 30, 28]
pessoas = [(i, nome, idade) for i, (nome, idade) in enumerate(zip(nomes, idades))]
print(pessoas) # [(0, 'Alice', 25), (1, 'Bob', 30), (2, 'Carol', 28)]
6. Casos de Uso Práticos no Dia a Dia
Transformação de dados:
# Converter temperaturas
temperaturas = [("São Paulo", 28), ("Rio", 32), ("Curitiba", 18)]
relatorio = [f"{cidade}: {c * 9/5 + 32:.1f}°F" for cidade, c in temperaturas]
# Normalizar valores para 0-1
valores = [10, 25, 40, 55, 70]
min_val, max_val = min(valores), max(valores)
normalizados = [(v - min_val) / (max_val - min_val) for v in valores]
Extração de atributos de objetos:
class Produto:
def __init__(self, nome, preco, estoque):
self.nome = nome
self.preco = preco
self.estoque = estoque
produtos = [Produto("Notebook", 3500, 10), Produto("Mouse", 50, 100)]
nomes_produtos = [p.nome for p in produtos]
produtos_caros = [p for p in produtos if p.preco > 1000]
Limpeza de dados:
dados_sujos = [10, None, 25, "", 30, 0, None, 15]
dados_limpos = [x for x in dados_sujos if x is not None and x != ""]
# [10, 25, 30, 0, 15]
# Remover duplicatas mantendo ordem
lista = [3, 1, 2, 1, 3, 4, 2, 5]
unicos = []
[unicos.append(x) for x in lista if x not in unicos]
print(unicos) # [3, 1, 2, 4, 5]
7. Limitações e Boas Práticas
List comprehensions não são adequadas para todas as situações:
Quando evitar:
- Complexidade excessiva: mais de 2-3 níveis de aninhamento
- Efeitos colaterais: comprehensions devem ser usadas para criar listas, não para executar ações
- Lógica muito condicional: múltiplos if-else aninhados na expressão
Mau exemplo (evitar):
# Complexo e difícil de ler
resultado = [
a if a > b else b
for a in range(10)
for b in range(10)
if a != b and (a + b) % 2 == 0
]
Alternativas recomendadas:
- Generator expressions para grandes volumes: (x**2 for x in range(10**6))
- Loops explícitos para lógica muito condicional ou com efeitos colaterais
8. Considerações de Performance
List comprehensions são geralmente mais rápidas que loops for tradicionais em Python puro, pois a interpretação do bytecode é otimizada para esta construção:
import timeit
# Loop tradicional
def loop_tradicional():
resultado = []
for i in range(1000):
resultado.append(i ** 2)
return resultado
# List comprehension
def comprehension():
return [i ** 2 for i in range(1000)]
# A comprehension é tipicamente 10-20% mais rápida
No entanto, é importante considerar o uso de memória: list comprehensions criam a lista completa na RAM. Para conjuntos de dados muito grandes, prefira generator expressions ou loops com yield.
Comparação com map() e filter():
# map + filter
list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, range(10))))
# Comprehension equivalente (mais pythonica)
[x**2 for x in range(10) if x % 2 == 0]
A versão com comprehension é geralmente preferida por ser mais legível e expressiva, seguindo o princípio "explicit is better than implicit" do Zen do Python.
Referências
- Python Documentation: List Comprehensions — Documentação oficial do Python com a sintaxe completa e exemplos básicos de list comprehensions.
- Real Python: When to Use a List Comprehension in Python — Tutorial abrangente cobrindo desde conceitos básicos até casos de uso avançados e boas práticas.
- PEP 202 – List Comprehensions — Proposta original que introduziu list comprehensions no Python 2.0, com discussões sobre design e motivação.
- GeeksforGeeks: Python List Comprehension — Guia prático com múltiplos exemplos de uso, incluindo aninhamento e condicionais.
- Python Like You Mean It: List Comprehensions — Recurso educacional com exemplos detalhados e exercícios práticos sobre list comprehensions.
- DataCamp: Python List Comprehension Tutorial — Tutorial interativo com exemplos do mundo real e comparações de performance entre comprehensions e loops tradicionais.