Programação Funcional para Acelerar Processamento de Dados em Python
1. Conceitos Fundamentais
1.1 Funções puras
Funções que não têm efeitos colaterais e retornam sempre o mesmo resultado para os mesmos parâmetros.
def soma(x, y):
return x + y
Evita dependência de estados externos, facilitando paralelização.
1.2 Imutabilidade
Dados não devem ser modificados no lugar.
Facilita processamento concorrente sem risco de condições de corrida.
lista = [1, 2, 3]
nova_lista = [x * 2 for x in lista] # cria nova lista
1.3 Funções de alta ordem
Funções que recebem funções como argumento ou retornam funções.
def aplica(func, lista):
return [func(x) for x in lista]
resultado = aplica(lambda x: x**2, [1,2,3])
print(resultado) # [1,4,9]
2. Funções Built-in Funcionais
2.1 map
Aplica uma função a todos os elementos de um iterável.
dados = [1,2,3,4]
resultado = list(map(lambda x: x*2, dados))
print(resultado) # [2,4,6,8]
Mais eficiente que loops convencionais em alguns casos, pois aproveita iteradores internos.
2.2 filter
Filtra elementos com base em uma condição.
pares = list(filter(lambda x: x % 2 == 0, dados))
print(pares) # [2,4]
2.3 reduce
(functools)
Reduz uma lista a um único valor.
from functools import reduce
soma_total = reduce(lambda x, y: x+y, dados)
print(soma_total) # 10
3. Compreensões e Generators
3.1 List Comprehension
Forma mais legível e eficiente que loops convencionais.
quadrados = [x**2 for x in range(1000)]
3.2 Generator Expressions
Evita criar listas grandes na memória, útil para datasets massivos.
gen = (x**2 for x in range(10**6))
Pode ser usado com
sum
,max
,min
sem criar lista intermediária.
4. Funções Parcial e Currying
4.1 functools.partial
Cria funções com parâmetros pré-definidos, útil em pipelines de dados.
from functools import partial
def potencia(base, expoente):
return base ** expoente
quadrado = partial(potencia, expoente=2)
print(quadrado(5)) # 25
4.2 Currying
Transformar funções de múltiplos argumentos em cadeias de funções de um argumento.
def soma(x):
return lambda y: x + y
add5 = soma(5)
print(add5(3)) # 8
5. Paralelização Funcional
Funções puras e imutáveis permitem processamento paralelo seguro:
5.1 concurrent.futures
com map
from concurrent.futures import ThreadPoolExecutor
def processa(x):
return x**2
dados = range(10**6)
with ThreadPoolExecutor() as executor:
resultados = list(executor.map(processa, dados))
Ideal para processamento de dados intensivo em CPU ou IO.
Com funções puras, não há riscos de conflito de estado.
5.2 Dask e pandas
Dask permite aplicar map, filter e reduce em datasets distribuídos.
Pandas também permite aplicar funções puras com
apply
em colunas para processamento vetorizado.
import pandas as pd
df = pd.DataFrame({'x': range(5)})
df['quadrado'] = df['x'].map(lambda x: x**2)
Evita loops explícitos, usando otimizações internas.
6. Decorators para Funções Funcionais
Podemos decorar funções puras para medir performance ou memoização.
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(35)) # computa rapidamente graças ao cache
Funciona bem em processamento recursivo intensivo.
7. Boas Práticas Profissionais
Prefira funções puras e evite efeitos colaterais.
Use map/filter/reduce ou compreensões sempre que possível.
Para grandes datasets, use generators e lazy evaluation.
Combine programação funcional com paralelização e memoization.
Documente pipelines de dados, deixando claro fluxo de transformação funcional.
Evite misturar estados mutáveis em funções puras, para não introduzir bugs difíceis de detectar.
8. Conclusão
Programação funcional em Python tornou-se essencial para processamento eficiente de dados.
Funções puras, imutabilidade, map/filter/reduce, generators e memoization permitem otimizar memória e tempo de execução.
Combinando com paralelização e frameworks como Dask, é possível processar milhões de registros de forma escalável e segura.
Esse paradigma é especialmente útil em data science, machine learning e pipelines de ETL.
Comentários
Postar um comentário