Dict e set comprehensions
1. Introdução às Comprehensions para Dicionários e Conjuntos
As comprehensions são construções sintáticas elegantes do Python que permitem criar coleções de forma concisa e expressiva. Enquanto list comprehensions são amplamente conhecidas, dict e set comprehensions oferecem poder semelhante para dicionários e conjuntos.
A sintaxe básica de um dict comprehension é:
{chave: valor for item in iterável}
Já para set comprehensions:
{expressão for item in iterável}
A diferença fundamental está nos colchetes ([]) para listas versus chaves ({}) para dicionários e conjuntos. Dict comprehensions produzem pares chave-valor separados por dois-pontos, enquanto set comprehensions geram valores únicos.
2. Dict Comprehensions: Sintaxe e Exemplos Práticos
Dict comprehensions permitem criar dicionários de forma declarativa. Vejamos exemplos práticos:
# Mapeamento simples: quadrados dos números
quadrados = {x: x**2 for x in range(5)}
print(quadrados) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# Criando dicionário a partir de pares de listas
nomes = ['Ana', 'Bruno', 'Carla']
idades = [25, 30, 22]
pessoas = {nome: idade for nome, idade in zip(nomes, idades)}
print(pessoas) # {'Ana': 25, 'Bruno': 30, 'Carla': 22}
# Usando enumerate() para criar dicionários indexados
frutas = ['maçã', 'banana', 'laranja']
indices = {i: fruta for i, fruta in enumerate(frutas)}
print(indices) # {0: 'maçã', 1: 'banana', 2: 'laranja'}
É possível também transformar listas de tuplas em dicionários:
pares = [('a', 1), ('b', 2), ('c', 3)]
dicionario = {k: v for k, v in pares}
print(dicionario) # {'a': 1, 'b': 2, 'c': 3}
3. Set Comprehensions: Sintaxe e Casos de Uso
Set comprehensions são ideais para criar conjuntos de elementos únicos de forma eficiente:
# Restos de divisão únicos
restos = {x % 3 for x in range(10)}
print(restos) # {0, 1, 2}
# Comprimentos únicos de palavras em um texto
texto = "Python é uma linguagem Python é poderosa"
comprimentos = {len(palavra) for palavra in texto.split()}
print(comprimentos) # {1, 2, 4, 6, 7, 9}
# Filtrando números pares únicos
numeros = [1, 2, 2, 3, 4, 4, 5, 6]
pares_unicos = {x for x in numeros if x % 2 == 0}
print(pares_unicos) # {2, 4, 6}
A diferença entre set comprehension e set() com generator expression é sutil:
# Set comprehension (mais direta)
s1 = {x**2 for x in range(1000)}
# Generator expression convertida para set
s2 = set(x**2 for x in range(1000))
# Ambas produzem o mesmo resultado, mas a sintaxe set comprehension é mais legível
4. Condicionais em Dict e Set Comprehensions
Condicionais permitem filtrar e transformar dados durante a criação:
# Filtragem com if
pares_quadrados = {x: x**2 for x in range(10) if x % 2 == 0}
print(pares_quadrados) # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
# Uso de if-else ternário na expressão de valor
classificacao = {x: 'par' if x % 2 == 0 else 'impar' for x in range(5)}
print(classificacao) # {0: 'par', 1: 'impar', 2: 'par', 3: 'impar', 4: 'par'}
# Combinação de múltiplas condições
dados = {x: x**2 for x in range(20) if x > 5 and x % 3 == 0}
print(dados) # {6: 36, 9: 81, 12: 144, 15: 225, 18: 324}
5. Comprehensões Aninhadas (Nested Comprehensions)
Comprehensions aninhadas permitem trabalhar com estruturas multidimensionais:
# Dict comprehension com loops aninhados para matriz
matriz = {(i, j): i * j for i in range(3) for j in range(3)}
print(matriz)
# {(0, 0): 0, (0, 1): 0, (0, 2): 0, (1, 0): 0, (1, 1): 1, (1, 2): 2, (2, 0): 0, (2, 1): 2, (2, 2): 4}
# Set comprehension aninhada para combinações únicas
combinacoes = {i + j for i in range(3) for j in range(3)}
print(combinacoes) # {0, 1, 2, 3, 4}
# Mapeamento bidimensional com condicional
pares_matriz = {(i, j): i * j for i in range(4) for j in range(4) if i != j}
É importante equilibrar legibilidade: para estruturas muito complexas, loops tradicionais aninhados podem ser mais claros:
# Alternativa com loops tradicionais (mais legível para casos complexos)
resultado = {}
for i in range(3):
for j in range(3):
if i != j:
resultado[(i, j)] = i * j
6. Operações Avançadas: Intercâmbio Chave-Valor e Transformações
Dict comprehensions são poderosas para transformações e manipulações de dicionários:
# Invertendo chaves e valores
original = {'a': 1, 'b': 2, 'c': 3}
invertido = {v: k for k, v in original.items()}
print(invertido) # {1: 'a', 2: 'b', 3: 'c'}
# Aplicando funções nos valores
dados = {'nome': 'ana', 'cidade': 'são paulo'}
formatado = {k: v.upper() for k, v in dados.items()}
print(formatado) # {'nome': 'ANA', 'cidade': 'SÃO PAULO'}
# Mesclando múltiplos dicionários
dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}
dict3 = {'e': 5}
lista_dicts = [dict1, dict2, dict3]
mesclado = {k: v for d in lista_dicts for k, v in d.items()}
print(mesclado) # {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
# Transformação condicional com métodos
textos = {'fruta': 'banana', 'cor': 'amarelo', 'qtd': '5'}
processado = {k: v.capitalize() if isinstance(v, str) else v for k, v in textos.items()}
7. Comparação com Alternativas e Boas Práticas
Dict comprehension vs. loop for tradicional:
# Abordagem com loop (menos elegante)
resultado_for = {}
for x in range(1000):
resultado_for[x] = x**2
# Dict comprehension (mais concisa e geralmente mais rápida)
resultado_comp = {x: x**2 for x in range(1000)}
Set comprehension vs. filter() + lambda:
numeros = range(20)
# Set comprehension (recomendada)
pares_set = {x for x in numeros if x % 2 == 0}
# filter + lambda (menos legível)
pares_filter = set(filter(lambda x: x % 2 == 0, numeros))
Boas práticas e limitações:
- Use comprehensions para transformações simples e diretas
- Evite comprehensions com efeitos colaterais (como
print()dentro da expressão) - Para expressões muito complexas, prefira loops tradicionais
- Mantenha a expressão em uma única linha sempre que possível
- Use nomes de variáveis claros e significativos
Quando evitar comprehensions:
# Exemplo de má prática (expressão muito complexa)
dados_complexos = {
k: (lambda x: x**2 if x % 2 == 0 else x**3)(v)
for k, v in enumerate(range(20))
if all(v % i != 0 for i in range(2, int(v**0.5) + 1))
}
# Melhor: separar em funções auxiliares
def transformar_valor(v):
return v**2 if v % 2 == 0 else v**3
def eh_primo(v):
return all(v % i != 0 for i in range(2, int(v**0.5) + 1))
dados_melhores = {k: transformar_valor(v) for k, v in enumerate(range(20)) if eh_primo(v)}
Dict e set comprehensions são ferramentas poderosas que tornam o código Python mais expressivo e eficiente. Quando usadas adequadamente, elas melhoram significativamente a legibilidade e a manutenibilidade do código, além de frequentemente oferecerem melhor desempenho que suas contrapartes com loops tradicionais.
Referências
- Python Documentation: Dictionary Comprehensions — Documentação oficial do Python explicando a sintaxe e uso de dict comprehensions
- Python Documentation: Set Comprehensions — Documentação oficial abordando set comprehensions e operações com conjuntos
- Real Python: Python Dictionary Comprehension — Tutorial completo com exemplos práticos e casos de uso avançados de dict comprehensions
- PEP 274: Dict Comprehensions — Proposta oficial que introduziu dict comprehensions na linguagem Python
- GeeksforGeeks: Python Set Comprehension — Guia detalhado sobre set comprehensions com exemplos e comparações de desempenho
- Towards Data Science: When to Use Python Comprehensions — Artigo sobre boas práticas e quando optar por comprehensions vs. loops tradicionais