map(), filter() e reduce() em Python: funções de ordem superior
Este tutorial foi traduzido do original em inglês.Read in EnglishLeer en españolЧитать на русскомอ่านภาษาไทยAvisar sobre um erro de tradução
Imagine a linha de montagem de uma fábrica. A matéria-prima entra por uma ponta. Na primeira estação, cada peça é moldada. Na seguinte, as peças com defeito são retiradas. Na última estação, todas as peças boas são combinadas em um único produto final.
O Python tem três funções que funcionam exatamente como essa linha de montagem: map() transforma cada item, filter() mantém só os itens que você quer e reduce() combina tudo em um único resultado. Juntas, elas permitem processar coleções de dados de um jeito limpo e legível.
Neste tutorial, você vai aprender como essas ferramentas funcionam, quando usá-las e quando uma list comprehension (compreensão de lista) pode ser uma escolha melhor. Ao final, você vai escrever pipelines de dados que deixariam qualquer supervisor de fábrica orgulhoso.
O que são funções de ordem superior?
Uma função de ordem superior é uma função que recebe outra função como argumento ou que retorna uma função como resultado. Só isso.
Você já usou uma sem perceber. A função embutida sorted() tem um parâmetro key no qual você passa uma função:
['apple', 'banana', 'cherry']
Aqui, len é passada como argumento para sorted(). A função sorted chama len em cada item para decidir a ordem. Você não chamou len() por conta própria: só disse a sorted qual função usar.
map(), filter() e reduce() funcionam todas assim. Você entrega a elas uma função e uma coleção, e elas aplicam essa função aos itens. É isso que as torna funções de ordem superior.
map(): transforme cada item
map() recebe uma função e um iterável (como uma lista), aplica a função a cada item e retorna os resultados transformados. Pense nela como a "estação de moldagem" da nossa linha de montagem.
A sintaxe é: map(function, iterable). Ela retorna um objeto map, que normalmente você converte em lista.
[2, 4, 6, 8, 10]
map(double, numbers) chama double(1), double(2), double(3) e assim por diante. Ela reúne todos os resultados. O list() em volta converte o objeto map em uma lista comum, para podermos exibi-la.
Como escrever uma função inteira só para dobrar um número parece exagero, map() costuma vir acompanhada de uma lambda, uma pequena função anônima:
[2, 4, 6, 8, 10] ['ALICE', 'BOB', 'CHARLIE'] [10, 20, 6]
Você pode passar qualquer função para map(): suas próprias funções, lambdas ou funções embutidas como str.upper, round, len ou int.
filter(): mantenha só o que você precisa
filter() recebe uma função e um iterável. A função precisa retornar True ou False para cada item. Só ficam os itens para os quais a função retorna True. Pense nela como o controle de qualidade da linha de montagem: as peças com defeito são retiradas.
[2, 4, 6, 8, 10]
filter(is_even, numbers) chama is_even(1), que retorna False (então o 1 é descartado), is_even(2) retorna True (então o 2 fica), e assim por diante. Só os itens que passam no teste sobrevivem.
['hello', 'world', 'python'] ['hello', 'world', 'python'] [2, 5, 8]
Passar bool para filter() é um truque esperto. Strings vazias, zero, None e listas vazias são todos "falsy" (contam como falso) em Python: bool() retorna False para eles. Então filter(bool, items) remove todos os valores falsy.
Combinando map() e filter()
O verdadeiro poder vem de encadear essas funções. Primeiro filtre para selecionar os itens, depois aplique map para transformá-los, exatamente como as estações de uma linha de montagem.
[87, 96, 72, 78, 93, 100, 65]
Como filter() e map() são preguiçosas, você pode encadeá-las sem criar listas intermediárias. Os dados passam pelo pipeline de forma eficiente.
Aqui está um exemplo mais prático, que processa uma lista de preços de produtos:
[10.39, 71.99, 36.0, 120.0]
reduce(): combine todos os itens em um só
reduce() recebe uma função e um iterável e combina todos os itens em um único valor. É a última estação da linha de montagem: todas as peças são montadas em um só produto.
Diferente de map() e filter(), reduce() não é uma função embutida. Você precisa importá-la do módulo functools.
Sum: 15 Product: 120
Veja como reduce() funciona, passo a passo, no caso da soma. A função recebe dois argumentos: o resultado acumulado até agora (a) e o próximo item (b):
a=1, b=2 dá 3a=3, b=3 dá 6a=6, b=4 dá 10a=10, b=5 dá 15Longest word: hippopotamus Alice & Bob & Charlie
map/filter versus compreensões de lista
O Python oferece outra forma de transformar e filtrar listas: as compreensões de lista (list comprehensions). Muitas vezes elas geram um código mais legível do que map() e filter(). Vamos comparar.
numbers = [1, 2, 3, 4, 5, 6]
# Double even numbers
evens = filter(lambda x: x % 2 == 0, numbers)
result = list(map(lambda x: x * 2, evens))
print(result) # [4, 8, 12]numbers = [1, 2, 3, 4, 5, 6]
# Double even numbers
result = [x * 2 for x in numbers if x % 2 == 0]
print(result) # [4, 8, 12]A compreensão faz a filtragem e o mapeamento em uma única linha legível. Para transformações simples, as compreensões costumam ser a melhor escolha em Python.
Então, quando usar map() e filter()? Elas são úteis quando você já tem uma função com nome para aplicar:
['Alice', 'Bob', 'Charlie'] ['Alice', 'Bob', 'Charlie']
Exercícios práticos
Hora de praticar. Estes exercícios começam com funções isoladas e avançam até combiná-las em pipelines. Lembre-se de envolver map() e filter() em list() na hora de exibir o resultado.
Use map() com uma lambda para elevar ao quadrado cada número da lista [1, 2, 3, 4, 5].
Exiba o resultado como uma lista.
Saída esperada:
[1, 4, 9, 16, 25]Use filter() com uma lambda para manter só as palavras com mais de 3 caracteres.
Dados: ["hi", "hello", "hey", "world", "ok", "python"]
Exiba o resultado como uma lista.
Saída esperada:
['hello', 'world', 'python']Leia este código e preveja a saída. Depois, escreva uma instrução print() que produza exatamente a mesma saída.
numbers = [10, 25, 30, 45, 50]
result = list(map(lambda x: x // 10, filter(lambda x: x >= 30, numbers)))
print(result)Pense passo a passo: o que filter mantém e, depois, o que map faz com cada item?
Este código deveria converter uma lista de temperaturas em texto, como ["32F", "100F", "212F"], em números inteiros em Celsius. Mas ele tem dois bugs.
Saída esperada:
[0, 38, 100]Fórmula: Celsius = (Fahrenheit - 32) * 5 / 9, depois arredonde para o inteiro mais próximo.
Use reduce() do módulo functools para calcular o produto de todos os números da lista [2, 3, 4, 5].
O produto é 2 * 3 * 4 * 5 = 120.
Exiba o resultado.
Saída esperada:
120Dada uma lista de notas de alunos, monte um pipeline que:
1. Remova as notas de reprovação (mantenha só as notas >= 60)
2. Ajuste cada nota aprovada somando 10 (use map)
3. Limite as notas a 100 (use map com min)
Dados: [45, 82, 55, 91, 67, 38, 73, 95]
Exiba a lista final.
Saída esperada:
[92, 100, 77, 83, 100]Dica: para limitar a 100, use min(score, 100).
Reescreva este pipeline de map/filter como uma única compreensão de lista que produza a mesma saída.
Código original:
words = ["Hello", "WORLD", "Python", "CODE", "test"]
result = list(map(str.lower, filter(lambda w: len(w) > 4, words)))Escreva uma compreensão de lista que produza o mesmo resultado e exiba-o.
Saída esperada:
['hello', 'world', 'python']Resumo
Veja o que você aprendeu sobre as ferramentas funcionais do Python:
| Função | Para que serve | Retorna |
|---|---|---|
map(fn, iterable) | Transformar cada item | Objeto map (preguiçoso) |
filter(fn, iterable) | Manter os itens para os quais fn retorna True | Objeto filter (preguiçoso) |
reduce(fn, iterable) | Combinar todos os itens em um único valor | Um único valor |
| Função de ordem superior | Uma função que recebe ou retorna uma função | Depende da função |
Na prática: use compreensões de lista na maioria das tarefas de transformar e filtrar em Python. Recorra a map() e filter() quando tiver uma função com nome para aplicar ou precisar de avaliação preguiçosa. Use reduce() com moderação: as funções embutidas do Python resolvem melhor a maioria dos casos.
O que vem a seguir?
Agora você tem uma base sólida em funções Python. Em seguida, explore o Tratamento de erros para aprender a escrever código que lida com erros de forma elegante, em vez de travar.