W3docs

Comprehensions de Dicionário e Conjunto em Python

Domine comprehensions de dicionário, conjunto e expressões geradoras em Python com sintaxe clara, exemplos reais e armadilhas comuns.

Comprehensions de dicionário, de conjunto e expressões geradoras estendem a sintaxe compacta de list comprehension para outras estruturas de dados. Este capítulo explica cada forma em profundidade — sintaxe, filtragem, aninhamento, padrões do mundo real e quando evitá-las.

Comprehensions de Dicionário

Uma comprehension de dicionário constrói um novo dict a partir de qualquer iterável em uma única expressão. Em vez de escrever um loop for que chama d[key] = value em cada iteração, você descreve o mapeamento de forma concisa dentro de chaves.

Sintaxe

new_dict = {key_expr: value_expr for item in iterable}

Adicione um filtro if opcional após o iterável:

new_dict = {key_expr: value_expr for item in iterable if condition}
ParteFunção
key_exprExpressão que produz cada chave
value_exprExpressão que produz cada valor
itemVariável do loop — assume cada valor do iterable por vez
if conditionFiltro opcional — ignora itens onde condition é False

Exemplo Básico: Construindo um Mapa de Quadrados

squares = {x: x ** 2 for x in range(1, 6)}
print(squares)
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

O loop for equivalente:

squares = {}
for x in range(1, 6):
    squares[x] = x ** 2

Ambos produzem o mesmo resultado; a forma de comprehension é mais concisa e expressa a intenção de relance.

Filtrando Entradas

Mantenha apenas os pares que satisfazem uma condição:

prices = {"apple": 1.20, "banana": 0.50, "orange": 0.80, "grape": 2.50}

expensive = {item: price for item, price in prices.items() if price >= 1.00}
print(expensive)
# {'apple': 1.2, 'grape': 2.5}

Transformando Valores

Aplique uma função ou expressão aritmética a cada valor:

prices = {"apple": 1.20, "banana": 0.50, "orange": 0.80}

# Apply a 10% discount and round to 2 decimal places
discounted = {item: round(price * 0.9, 2) for item, price in prices.items()}
print(discounted)
# {'apple': 1.08, 'banana': 0.45, 'orange': 0.72}

Trocando Chaves e Valores

Inverta um dicionário (funciona corretamente quando todos os valores são únicos):

capitals = {"France": "Paris", "Germany": "Berlin", "Japan": "Tokyo"}

inverted = {city: country for country, city in capitals.items()}
print(inverted)
# {'Paris': 'France', 'Berlin': 'Germany', 'Tokyo': 'Japan'}

Se os valores não forem únicos, entradas posteriores sobrescrevem as anteriores. Use isso apenas quando tiver certeza de que os valores formam um mapeamento um-para-um.

Construindo a partir de Dois Iteráveis com zip()

zip() emparelha itens de duas sequências, facilitando a construção de um dicionário a partir de listas separadas de chaves e valores:

keys = ["name", "age", "city"]
values = ["Alice", 30, "Berlin"]

profile = {k: v for k, v in zip(keys, values)}
print(profile)
# {'name': 'Alice', 'age': 30, 'city': 'Berlin'}

Isso equivale a dict(zip(keys, values)), mas a forma de comprehension facilita adicionar um filtro ou transformar valores ao mesmo tempo.

Normalizando Chaves

Uma tarefa comum do mundo real é limpar as chaves de um dicionário — por exemplo, converter todas as chaves para minúsculas ao mesclar dados de diferentes fontes:

raw = {"Name": "Alice", "AGE": 30, "City": "Berlin"}

normalised = {k.lower(): v for k, v in raw.items()}
print(normalised)
# {'name': 'Alice', 'age': 30, 'city': 'Berlin'}

Expressão de Valor Condicional (Ternário no Valor)

Você pode usar uma expressão ternária na posição do valor para escolher entre dois valores por item:

scores = {"Alice": 95, "Bob": 62, "Carol": 78, "Dave": 45}

grades = {name: "pass" if score >= 70 else "fail" for name, score in scores.items()}
print(grades)
# {'Alice': 'pass', 'Bob': 'fail', 'Carol': 'pass', 'Dave': 'fail'}

Comprehensions de Dicionário Aninhadas

Você pode aninhar uma comprehension para lidar com dados de múltiplos níveis. Por exemplo, extraindo um campo de uma lista de dicionários aninhados:

students = [
    {"name": "Alice", "score": 95, "grade": "A"},
    {"name": "Bob",   "score": 82, "grade": "B"},
    {"name": "Carol", "score": 91, "grade": "A"},
]

# Build a {name: score} mapping from the list
name_to_score = {s["name"]: s["score"] for s in students}
print(name_to_score)
# {'Alice': 95, 'Bob': 82, 'Carol': 91}

Mantenha o aninhamento raso. Se a lógica se tornar difícil de acompanhar, extraia uma função auxiliar ou use um loop for simples.

Comprehensions de Conjunto

Uma comprehension de conjunto constrói um set em uma única expressão. Como os conjuntos contêm apenas elementos únicos, duplicatas são removidas automaticamente.

Sintaxe

new_set = {expression for item in iterable}
new_set = {expression for item in iterable if condition}

A única diferença visual em relação a uma comprehension de dicionário é a ausência de dois-pontos — há uma expressão, não um par key: value.

Exemplo Básico: Quadrados Únicos

numbers = [1, 2, 2, 3, 3, 3, 4]
unique_squares = {x ** 2 for x in numbers}
print(unique_squares)
# {1, 4, 9, 16}

A ordem de saída não é garantida — os conjuntos não são ordenados, portanto não confie em uma ordem de exibição específica.

Deduplicando ao Transformar

Um padrão comum é normalizar strings e deduplicar em um único passo:

tags = ["Python", "python", "PYTHON", "Data", "data", "DATA"]

unique_tags = {tag.lower() for tag in tags}
print(unique_tags)
# {'python', 'data'}

Filtrando com uma Condição

words = ["cat", "elephant", "dog", "rhinoceros", "ant"]

long_words = {w for w in words if len(w) > 4}
print(long_words)
# {'elephant', 'rhinoceros'}

Encontrando Elementos Comuns

Comprehensions de conjunto se combinam naturalmente com operações de conjunto:

list_a = [1, 2, 3, 4, 5, 5, 6]
list_b = [4, 5, 6, 7, 8]

set_a = {x for x in list_a}
set_b = {x for x in list_b}

common = set_a & set_b
print(common)
# {4, 5, 6}

Para uma conversão direta sem transformação, set(list_a) é mais simples. Use uma comprehension de conjunto quando precisar filtrar ou transformar durante a conversão.

Expressões Geradoras

Uma expressão geradora parece uma list comprehension, mas usa parênteses em vez de colchetes. Em vez de construir toda a coleção na memória de uma vez, ela produz um valor por vez, sob demanda (de forma preguiçosa).

Sintaxe

gen = (expression for item in iterable)
gen = (expression for item in iterable if condition)

Por Que Usar uma Expressão Geradora?

CenárioList comprehensionExpressão geradora
Precisa iterar o resultado várias vezesSimNão — geradores são esgotados após uma passagem
Precisa de acesso aleatório por índice (result[3])SimNão
O resultado é passado para sum(), max(), any(), etc.Funciona, mas aloca uma listaPreferível — transmite valores sem construir uma lista
Sequência muito grande ou infinitaPode ficar sem memóriaEficiente — um valor por vez

Exemplo Básico

# List comprehension — builds the entire list in memory
squares_list = [x ** 2 for x in range(1, 6)]
print(squares_list)   # [1, 4, 9, 16, 25]

# Generator expression — yields values one at a time
squares_gen = (x ** 2 for x in range(1, 6))
print(squares_gen)    # <generator object <genexpr> at 0x...>
print(list(squares_gen))  # [1, 4, 9, 16, 25]

O objeto gerador em si não é a lista — você o consome iterando-o ou passando-o para uma função.

Passando Diretamente para Funções Integradas

Quando você passa uma expressão geradora como único argumento para uma função, pode omitir o par extra de parênteses:

total = sum(x ** 2 for x in range(1, 1001))
print(total)  # 333833500

maximum = max(len(word) for word in ["apple", "banana", "kiwi"])
print(maximum)  # 6

any_negative = any(x < 0 for x in [1, -2, 3])
print(any_negative)  # True

Vantagem de Memória

Para grandes volumes de dados, uma expressão geradora evita carregar tudo na RAM:

# Simulate a large log file as a list of strings
log_lines = [f"ERROR line {i}" if i % 100 == 0 else f"INFO line {i}" for i in range(1_000_000)]

# Generator scans lines without building an intermediate list
error_count = sum(1 for line in log_lines if line.startswith("ERROR"))
print(error_count)  # 10000

Geradores São Esgotados Após Uma Passagem

Esta é a armadilha mais comum:

gen = (x * 2 for x in range(5))

print(list(gen))  # [0, 2, 4, 6, 8]
print(list(gen))  # [] — the generator is now empty

Se você precisar iterar o resultado mais de uma vez, use uma list comprehension ou recrie o gerador.

Encadeando Expressões Geradoras

Expressões geradoras podem ser compostas sem criar listas intermediárias. Cada estágio puxa valores do anterior:

numbers = range(1, 11)

# Stage 1: filter even numbers
evens = (x for x in numbers if x % 2 == 0)

# Stage 2: square them
even_squares = (x ** 2 for x in evens)

print(list(even_squares))  # [4, 16, 36, 64, 100]

Nenhuma lista intermediária é criada — os valores fluem pelo pipeline um de cada vez.

Escolhendo a Forma Certa

Você precisa de…Use
Uma lista de valores transformados/filtrados[expr for item in it]
Um dicionário a partir de pares de valores{k: v for item in it}
Uma coleção sem duplicatas{expr for item in it}
Iteração de passagem única eficiente em memória(expr for item in it)
Lógica complexa com múltiplas instruções por itemLoop for simples

Armadilhas Comuns

Comprehension de dicionário vs. comprehension de conjunto. Ambas usam chaves {}. A diferença está em escrever key: value (dict) ou uma única expression (set). Um {} vazio sempre cria um dict vazio, não um conjunto vazio — use set() para um conjunto vazio.

d = {}     # empty dict
s = set()  # empty set — NOT {}

Chaves sobrescritas. Se a expressão de chave produzir duplicatas, valores posteriores silenciosamente sobrescrevem os anteriores:

data = [("a", 1), ("b", 2), ("a", 99)]
d = {k: v for k, v in data}
print(d)  # {'a': 99, 'b': 2} — first 'a' is gone

Escopo de variáveis. Em Python 3, a variável do loop em qualquer comprehension é local à comprehension e não vaza para o escopo circundante:

x = "original"
result = {x: x.upper() for x in ["a", "b", "c"]}
print(x)  # 'original' — comprehension's x did not overwrite this

Limite de legibilidade. Se você precisar de mais de uma condição if ou a expressão for longa, um loop for simples com nomes de variáveis descritivos costuma ser mais claro:

# Hard to read
result = {k: v for k, v in data.items() if k.startswith("user_") if v is not None}

# Easier to read
result = {}
for k, v in data.items():
    if k.startswith("user_") and v is not None:
        result[k] = v

Tópicos Relacionados

Prática

Prática
Which of the following statements about Python comprehensions is correct?
Which of the following statements about Python comprehensions is correct?
Was this page helpful?