Compreensões
Esta aula ensina as compreensões em Python, incluindo list, dict e set comprehensions, generator expressions, aninhamento e considerações de legibilidade. Você aprenderá a escrever código mais conciso e eficiente, com exemplos práticos e exercícios.
Compreensões (comprehensions) são uma construção sintática poderosa em Python que permite criar sequências de forma concisa e expressiva. Elas substituem loops tradicionais de mapeamento e filtragem, tornando o código mais legível e, em muitos casos, mais rápido. Nesta aula, exploraremos comprehensions para listas, dicionários e conjuntos, além de generator expressions e como aninhá-las.
Dominar comprehensions é essencial para escrever código Python idiomático. Elas são amplamente utilizadas em projetos reais, desde processamento de dados até scripts de automação. Vamos ver cada tipo com exemplos práticos.
List, dict e set comprehensions
As comprehensions permitem criar listas, dicionários e conjuntos em uma única linha, com uma sintaxe que lembra a notação matemática de conjuntos. A estrutura básica é: [expressão for item in iterável if condição] para listas; {chave: valor for item in iterável if condição} para dicionários; e {expressão for item in iterável if condição} para conjuntos.
Por exemplo, para criar uma lista de quadrados dos números pares de 0 a 9, podemos usar uma list comprehension em vez de um loop for com append:
# Loop tradicional
quadrados = []
for i in range(10):
if i % 2 == 0:
quadrados.append(i**2)
print(quadrados) # [0, 4, 16, 36, 64]
# List comprehension
quadrados = [i**2 for i in range(10) if i % 2 == 0]
print(quadrados) # [0, 4, 16, 36, 64]Para dicionários, podemos criar um mapeamento de números para seus cubos apenas para números ímpares:
cubos = {i: i**3 for i in range(10) if i % 2 != 0}
print(cubos) # {1: 1, 3: 27, 5: 125, 7: 343, 9: 729}E para conjuntos, removendo duplicatas automaticamente:
letras = 'abracadabra'
unicas = {letra for letra in letras}
print(unicas) # {'a', 'b', 'c', 'd', 'r'}Generator expressions
Generator expressions são semelhantes às list comprehensions, mas usam parênteses em vez de colchetes e produzem um objeto gerador, que é lazy: ele gera os valores sob demanda, sem armazenar toda a sequência na memória. Isso é útil para grandes volumes de dados.
Exemplo: somar os quadrados de 1 a 1.000.000 sem criar uma lista gigante:
soma = sum(x**2 for x in range(1, 1000001))
print(soma) # 333333833333500000Note que não há colchetes dentro do sum, apenas parênteses. Isso é uma generator expression. Você também pode usar generator expressions em funções que aceitam iteráveis, como any, all, min, max.
Para iterar explicitamente sobre um gerador, você pode usar um loop for ou convertê-lo para lista (perdendo a vantagem de memória):
gen = (x**2 for x in range(5))
for valor in gen:
print(valor)Aninhamento
Compreensões podem ser aninhadas, ou seja, você pode ter múltiplos for dentro de uma comprehension. Isso é útil para trabalhar com estruturas aninhadas, como matrizes.
Por exemplo, para achatar uma matriz 2D em uma lista:
matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
plana = [num for linha in matriz for num in linha]
print(plana) # [1, 2, 3, 4, 5, 6, 7, 8, 9]A ordem dos loops na comprehension segue a mesma ordem que em loops aninhados tradicionais: primeiro o loop externo, depois o interno. Você também pode adicionar condições. Por exemplo, para obter apenas números pares da matriz:
pares = [num for linha in matriz for num in linha if num % 2 == 0]
print(pares) # [2, 4, 6, 8]Aninhamento também funciona para dicionários e conjuntos. Por exemplo, criar um dicionário com pares (linha, coluna) para elementos não nulos:
matriz = [[1, 0, 3], [0, 5, 0]]
nao_nulos = {(i, j): valor for i, linha in enumerate(matriz) for j, valor in enumerate(linha) if valor != 0}
print(nao_nulos) # {(0, 0): 1, (0, 2): 3, (1, 1): 5}Legibilidade
Embora comprehensions sejam concisas, abusar delas pode prejudicar a legibilidade. Uma boa prática é limitar o aninhamento a, no máximo, dois níveis. Se a lógica ficar muito complexa, prefira loops explícitos ou funções auxiliares.
Por exemplo, esta comprehension é difícil de ler:
result = [a for b in c for d in e if f(d) for g in h if i(g)]Em vez disso, divida em etapas ou use loops. Além disso, evite efeitos colaterais dentro de comprehensions (como print). Comprehensions são para construir sequências, não para executar ações.
Outra dica: use nomes de variáveis descritivos. Por exemplo, [num * 2 for num in numeros] é mais claro que [x * 2 for x in y].
Boas práticas e observações finais
Prefira list comprehensions a map e filter quando a lógica envolver lambdas simples, pois comprehensions são mais legíveis. Use generator expressions para grandes volumes de dados para economizar memória. Lembre-se de que comprehensions criam uma nova sequência; se você precisar modificar uma existente, loops podem ser mais adequados.
Referências
- Documentação oficial: List Comprehensions
- Documentação oficial: Dictionaries
- Documentação oficial: Sets
- Documentação oficial: Generator expressions
- Real Python: List Comprehensions
- W3Schools: List Comprehension
- PEP 202 – List Comprehensions
Exercícios
Crie uma list comprehension que gere uma lista dos quadrados dos números ímpares de 1 a 20.
✓ Resposta:[i**2 for i in range(1, 21) if i % 2 != 0]Dada uma lista de palavras, crie um dicionário que mapeie cada palavra ao seu comprimento, apenas para palavras com mais de 3 letras.
✓ Resposta:palavras = ['casa', 'sol', 'python', 'a', 'programacao'] comprimentos = {palavra: len(palavra) for palavra in palavras if len(palavra) > 3} print(comprimentos) # {'casa': 4, 'python': 6, 'programacao': 11}Use uma generator expression para calcular a soma dos cubos dos números de 1 a 1000.
✓ Resposta:soma = sum(x**3 for x in range(1, 1001)) print(soma) # 250500250000Dada uma matriz 3x3 (lista de listas), use uma list comprehension aninhada para extrair todos os elementos da diagonal principal.
✓ Resposta:matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] diagonal = [matriz[i][i] for i in range(len(matriz))] print(diagonal) # [1, 5, 9]Reescreva o seguinte loop usando uma set comprehension:
letras_unicas = set()for char in 'banana':if char not in 'aeiou':letras_unicas.add(char)✓ Resposta:letras_unicas = {char for char in 'banana' if char not in 'aeiou'} print(letras_unicas) # {'b', 'n'}