Programação funcional em Python

Publicado por Danillo Souza em 12/05/2010

[ Hits: 13.860 ]

 


Programação funcional em Python



A programação funcional é um paradigma que se baseia inteiramente no uso de funções, ou seja, você pensa em programação funcional como simplesmente avaliações de funções, onde uma função pode ser complementada com outra(s) função(ões).

Mas qual a vantagem disso?

Bom, geralmente linguagens que implementam o paradigma funcional possuem algumas funções/recursos especialmente para esse paradigma, que visa tornar os programas mais ágeis, curtos, concisos, e menos suscetíveis a erros de estruturação.

Existem linguagens puramente funcionais (como é o caso de Lisp, que tem seu uso voltado 95% para inteligência artificial) e linguagens multiparadigmas, que é o caso de Python (onde você pode programar no paradigma procedural, orientado a objetos, funcional...).

Vamos então ver as estruturas que nos permitem trabalhar funcionalmente com Python:

sum

A mais básica. Ela recebe uma lista e devolve a soma e todos os seus valores

sum( range(11) ) # somando todos os números até 10

Resultado seria 55.

lambda

Funções lambda são funções anônimas, ou seja, não são reutilizáveis (na verdade podem ser sim, mas não foram feitas pra isso e você já vai entender o por que em alguns "episódios").

Daí você se pergunta:

"Qual a utilidade de uma função se ela não pode ser reutilizada?"

Daí eu te falo, tenta imaginar alguma relação entre lambdas e processamento de listas (sacô sacô?).

Para criar uma lambda fazemos assim:

lambda <argumentos> : <expressão>

Onde <argumentos> é a lista de argumentos que serão passados para a função (dificilmente você precisará usar mais do que 1) e <expressão> é uma expressão avaliando os argumentos e retornando seu valor.

Você pode atribuir uma lambda a uma variável e então reutilizá-la (esse pode ser um jeito curto de escrever funções curtas, mas o objetivo de lambda não é esse).

f = lambda x: x*2
f(2) # retorna 4

Agora sim, no próximo parágrafo vamos ver a real utilidade de lambdas...

map

Map é uma função que "mapeia" uma lista em uma função, e seu uso é:

map(<função>, <lista>)

Explicando, map retorna uma lista com os resultados de cada valor da lista original submetido a função, vamos ver um exemplo prático disso (mão na cabeça que vai começaaar.).

lista = range(1, 11) # lista de 1 a 10.. sim,de 1 a 10, o 11 é exclusivo
nova_lista = map(lambda x:x*2, lista)
for i in nova_lista:
   print i

A saída seria:

2
4
6
8
10
12
14
16
18
20

Perceberam como lambda é útil? Essa é uma aplicação simples, mas imagine algo mais complexo (programação funcional aplicada pode ser muito complexa).

filter

Exatamente, é um filtro. Ele funciona quase igual ao map, retorna uma lista, mas a diferença é que a função que ele aplica aos elementos da lista é uma função que retorna verdadeiro ou falso, e ele só retorna na nova lista os elementos que passarem pela função e retornarem verdadeiro.

Vamos ver um exemplo de uma função que só retorna números pares:

lista = range(1, 11)
nova_lista = filter(lambda x: x % 2 == 0, lista)
for i in nova_lista:
   print i

Saída:

2
4
6
8
10

Bem fácil de sacar né? :D

reduce

Bom, pode parecer complicada mas é bem fácil.

É o seguinte, nas funções acima nós usamos lambdas de apenas 1 argumento certo? Como reduce é uma daquelas exceções onde você vai usar 2. Ela funciona aplicando os argumentos de 2 em 2, e é acumulativa, ou seja, numa lambda;

lambda x,y: x + y

E suponhamos que a lista seja de 1 a 10, o reduce faria:

1 + 2   = 3
3 + 3   = 6
6 + 4   = 10
10 + 5  = 15
15 + 6  = 21
21 + 7  = 28
28 + 8  = 36
36 + 9  = 45
45 + 10 = 55

Entenderam? A saída acima seria gerada pela seguinte reduce:

lista = range(1, 11)
nova_lista = reduce(lambda x,y: x+y, lista)
for i in nova_lista:
   print i

Sacaram né? Bem molezinha e útil. :D

zip

Nossa última "arma" funcional, e não, ela não compacta arquivos. ;)

O que a função zip faz é receber várias listas e retornar uma lista contendo N tuplas (iguais as listas, mas são imutáveis), onde N é o número de elementos da maior lista fornecida.

Essas tuplas são agrupamentos de elementos de mesmo índice, de todas as listas, e caso as listas sejam de tamanhos diferentes, os valores que estiverem faltando são preenchidos com "None".

Vamos ver:

list1 = range(1, 6) # de 1 a 5
list2 = range(11, 16) # de 11 a 15
tuplas = zip(list1, list2)
print tuplas

A saída do programa seria:

[(1, 11), (2, 12), (3, 13), (4, 14), (5, 15)]

Reparem que cada tupla é um agrupamento de elementos de índices iguais(primeira tuplas contem os elementos de índices 0, a segunda de índices 1 etc).

Essa eu particularmente gosto de usar para transformar linhas em colunas, e colunas em linhas, em matrizes não muito grandes.

No projeto Euler, o primeiro problema proposto foi calcular a soma de todos os números abaixo de 1000 que fossem divisíveis tanto por 3 quanto por 5(não apenas por um, mas por ambos).. É fácil, você faria isso em poucas linhas.

Programando funcionalmente em Python, você faria em uma:

sum(filter(lambda x: not(x % 5 and x % 3), range(1000)))

Bom, é isso aí pessoal, espero que tenham gostado.

Té mais \õ/

Outras dicas deste autor

Gerando gráficos com Pylab

Criando listas individuais para cada instância da mesma classe em Python

Leitura recomendada

Python 3 no Funtoo Linux

Reproduzindo somente áudio com o mplayer

Backup do Outlook de uma estação com Windows XP

Removendo Kernel Antigo do Ubuntu

Como inicar o Tomcat no modo debug no Linux

  

Comentários
[1] Comentário enviado por rafaelhenrique em 12/05/2010 - 15:32h

Excelente dica, valeu Danilo

[2] Comentário enviado por andrezc em 13/05/2010 - 16:12h

Aprovado :D

[3] Comentário enviado por gabrielbap em 29/06/2011 - 14:18h

Gostei da dica, ficou mais fácil entender a programação funcional.
Mas o último código parece estar errado, testei fazendo apenas o filter (sem somar o total) e ele retornou tanto os divisíveis apenas por 3 quanto os divisíveis apenas por 5.
Acho que o correto seria:

sum(filter(lambda x:(not x%5 and not x%3), range(1000)))



Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts