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