O objetivo desse post é apresentar da forma simples e fácil de algumas das características do paradigma funcional aplicado na linguagem de programação Python. Como existem inúmeras literaturas na web falando sobre o que séria programação funcional e a sua diferença em relação a outros paradigmas optei por focar nas seguinte característica:
- Expressão lambda
- Funções de alta ordem: map(), filter(), reduce() e zip()
Importante:
O aspecto funcional de Python permite escrever código compacto e
eventualmente mais rápido, por outro lado corre-se o risco de deixar
o código obscuro e de manutenção mais complicada.
permite
escrever funções anônimas/sem-nome usando apenas uma linha de
código.
Sintaxe:
lambda [ var1, var2, ..., varN ]: expr -> expr_ret
Onde
var1,
var2, ..., varN são
variáveis que representam o argumento da função e expr
é
qualquer expressão válida em Python envolvendo essas variáveis.O
resultado é uma nova expressão expr_ret.
Um
exemplo trivial de lamba é a função identidade, que retorna o
próprio elemento. Um exemplo prático de lambda é uma função que
recebe dois valores (x e y) e retorna a soma desses elementos.
Função identidade.
lambda x:
x
Resultado: <function <lambda>
at 0x1e3630>
Soma de dois valores.
lambda x, y: x+y
Resultado:<function <lambda> at 0x1e3670>
Note que o resultado é
uma expressão do tipo lambda. Mas como posso obter algo útil, por
exemplo, calcular 1+2 com lambda?
(lambda x, y: x+y)(1,2) Resultado: 3 Esta forma de expressar um função é conhecida como função anonima, visto que a função não recebe um nome especifico pra ela.Agora caso queira dar um nome para ajudar a "lembrar" uma expressão lambda é necessário apenas guardá-la em uma variável.
identidade = lambda x: x
identidade('Python')
Resultado'Python'
soma = lambda x, y: x+y
soma(1, 2)
Resultado:3
Aparentemente lambda sozinho não tem muita
graça ou utilidade, mas nas seções que se seguem faremos melhor
uso dela. O importante é ter em mente que uma expressão lambda pode
responder igual a qualquer função em Python.
Mapeamento - Map
O
mapeamento consiste em aplicar uma função a todos os itens de uma
sequência, gerando outra lista contendo os resultados e com o mesmo
tamanho da lista inicial.
A
forma mais simples de se usar o map é aplicando uma função função
uma sequência
seq,
o resultado é sempre uma lista cujo os elementos são obtidos
aplicando-se individualmente cada elemento de seq a função func. Ao
mapear-se uma lista com None
retorna-se
os elementos originais da sequência.
Sintaxe:
map(funcão
ou None,
seq) ->lista
map(None, [1, 3, 5])
resultado: [1, 3, 5]
map(abs, [-1, -2, -3])
Resultado: [1, 2, 3]
map(str, [2, 4, 6])
Resultado: ['2', '4', '6']
map(hex, (10, 11, 12))
Resulado: ['0xa', '0xb', '0xc']
Um exemplo mais interessante com uso da expressão lambda.
Resultado: [1, 8, 27, 64]
Forma Completa de Map
A
forma completa de map admite uma função func
(ou
None)
e um conjunto de sequencias
(seq1,
seq2, ..., seqN)
como parâmetros.
map(func ou None,
seq1, seq2,
..., seqN) ->lista
Atribuindo-se
None
ao
map este retorna sempre uma tupla de N elementos que são os
elementos cuja ordem deles é a ordem das sequencias
até o tamanho da maior lista, índices maiores que as
sequências
são retornados como None.
map(None,
[1, 3, 5],
[2, 4, 6])
[(1, 2), (3, 4), (5, 6)]
map(None, [1, 3, 5], [2, 4, 6, 8, 10])
[(1, 2), (3, 4), (5, 6), (None, 8), (None, 10)]
Fica fácil entender que se oferecermos ao map três listas é
necessário então que a função aceite três variáveis como
parâmetro. As seqüencias menoresque M são automaticamente
preenchidas com o valor None e isso pode ser um inconveniente
caso se tente aplicar a uma função que espera valores
numéricos, pois None nunca é tratado como um valor numérico.
[2, 12, 30]
map(lambda a, b, x: a*x+b, [1, 3, 5], [2, 4, 8], [0, 0, 0])
[2, 4, 8]
Redução – reduce
Redução
significa aplicar uma função que recebe dois parâmetros, nos dois
primeiros elementos de uma sequência, aplicar novamente a função
usando como parâmetros o resultado do primeiro par e o terceiro
elemento, seguindo assim até o final da sequência. O resultado
final da redução é apenas um elemento.
A
função reduce
aplica
acumuladamente os itens
de uma sequência
de entrada seq
(da
esquerda para a direita) a uma função func
de
dois parâmetros até reduzir esse cálculo a um único valor de
resposta. Opcionalmente pode-se atribuir um valor inicial
como
parâmetro.
Sintaxe:
reduce(func, seq[, inicial]) -> valor
reduce(lambda x, y: x+y, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) Resultado:55 reduce(lambda x, y: x+y, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 100) Resultado:155 A função reduce() também pode ser usada para calcular fatorial: fatorial = lambda n: reduce(lambda x, y: x*y, range(1, n))
Filtragem - filter
Na
filtragem, uma função é aplicada em todos os itens de uma
sequência, se a função retornar um valor que seja avaliado como
verdadeiro, o item original fará parte da sequência resultante.
A
função filter
retorna
uma sequência
seq_ret
cujos
valores são os elementos da sequência
de entrada seq
que
respeitam o seguinte critério: se a função for None
os
elementos que são verdadeiros são adicionados, caso uma função
func
esteja
definida o valor de retorno da função é utilizado como valor
verdade e apenas esses elementos vão fazer parte da sequência
de retorno.
filter(func ou
None, seq)
-> seq_ret
filter(None,
[0, 1, 2,
None, 2>1,
'ola'])
filter(lambda x: x > 3, [0, 1, 2, 3, 4, 5])
Resultado:[4, 5]
filter(lambda s: s > 'a', 'python r0cks!')
Resultado:'pythonrcks'
filter(lambda x: x % 2, [1, 2, 3, 4, 5, 6, 7])
Transposição - Zip
Transposição
é construir uma série de sequências a partir de outra série de
sequências, aonde a primeira nova sequência contém o primeiro
elemento de cada sequência original, a segunda nova sequência
contém o segundo elemento de cada sequência original, até que
alguma das sequências originais acabe.
A
função zip
retorna
uma sequência
seq_ret
cujos
elementos são tuplas resultantes de cada um dos elementos de uma ou
mais sequências
de entradaseq1,
seq2, ..., seqN.
A sequência
resultante é sempre truncada ao tamanho da menor sequência
apresentada.
zip(seq1,
seq2, ..., seqN)
-> seq_ret
zip([1,
3, 5], [2,
4, 6])
zip([1, 3, 5], [2, 4, 6, 8, 10])
Resultado:[(1, 2), (3, 4), (5, 6)]
0 comentários:
Postar um comentário