8415
Comentário:
|
10011
|
Deleções são marcadas assim. | Adições são marcadas assim. |
Linha 1: | Linha 1: |
Programação Funcional em Python Rudá Moura <ruda@haxent.com.br> Dezembro de 2003 Resumo |
'''Programação Funcional em Python - Rudá Moura <ruda.moura@gmail.com><<BR>> Dezembro de 2003. Revisado em 2011.''' Resumo: |
Linha 18: | Linha 17: |
1. Primeiras Palavras |
<<TableOfContents>> = Primeiras Palavras = |
Linha 23: | Linha 23: |
A lista é um tipo de dado dinâmico (pode aumentar ou diminuir de tamanho) e | A ''lista'' é um tipo de dado dinâmico (pode aumentar ou diminuir de tamanho) e |
Linha 27: | Linha 27: |
O Python provê um conjunto de funções que podem ser aplicados a listas. Pode-se inserir ou remover elementos, classificar, tratar a lista como se |
O Python provê um conjunto de funções que podem ser aplicados as listas. Pode-se inserir ou remover elementos, classificar/ordenar, tratar a lista como se |
Linha 32: | Linha 32: |
{{{ #!python |
|
Linha 36: | Linha 38: |
Uma tupla é semelhante a uma lista mas esta é estática (não possui métodos para inserir ou remover elementos) e imutável (os elementos individuais não podem ser alterados). Uma string, que também é um tipo estático e imutável, pode ter um tratamento análogo ao de uma lista. Define-se então o termo seqüencia para indicar uma tupla, uma string ou uma lista. |
}}} Uma ''tupla'' é semelhante a uma lista mas esta é estática (não possui métodos para inserir ou remover elementos) e imutável (os elementos individuais não podem ser alterados). Um exemplo de tupla pode ser um par de elementos, como em (-1, 1) ou um conjunto de pares, como em ( (0, 0, 0), (1, 1, 1), (-1, -1, -1) ). Uma ''string'', que também é um tipo estático e imutável e pode ter um tratamento análogo ao de uma lista. Define-se então o termo genérico ''seqüência'' para indicar uma tupla, uma string ou uma lista. Note que não existe um tipo seqüência em Python. {{{ #!python |
Linha 47: | Linha 53: |
2. A Expressão Lambda Uma expressão lambda permite escrever funções anônimas ou sem-nome usando apenas uma linha de código. Sintaxe: |
}}} = A Expressão Lambda = Uma ''expressão lambda'' permite escrever funções anônimas/sem-nome usando apenas uma linha de código. Sintaxe: {{{ |
Linha 56: | Linha 63: |
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 prático de lambda é uma função que recebe dois valores (x e y) e retorna a soma desses elementos. Exemplos: |
}}} 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. Exemplos: Função identidade. {{{ #!python >>> lambda x: x <function <lambda> at 0x1e3630> }}} Soma de dois valores. {{{ #!python |
Linha 67: | Linha 85: |
<function <lambda> at 0x81a8d84> Como posso obter algo útil, por exemplo 1+2? |
<function <lambda> at 0x1e3670> }}} Note que o resultado é um tipo lambda. Mas como posso obter algo útil, por exemplo, calcular 1+2 com lambda? {{{ #!python |
Linha 73: | Linha 94: |
}}} | |
Linha 75: | Linha 97: |
{{{ #!python >>> identidade = lambda x: x >>> identidade('Python') 'Python' |
|
Linha 77: | Linha 103: |
>>> soma <function <lambda> at 0x81a8e2c> |
|
Linha 81: | Linha 105: |
}}} | |
Linha 86: | Linha 111: |
3. As Funções Embutidas Map, Reduce, Filter e Zip. 3.1. Map A forma mais simples de se usar o map é aplicando uma função func a uma seqüência seq, o resultado é sempre uma lista cujo os elementos são obtidos |
= As Funções Embutidas Map, Reduce, Filter e Zip = == Map == A forma mais simples de se usar o map é aplicando uma função ''func'' a uma seqüência ''seq'', o resultado é sempre uma lista cujo os elementos são obtidos |
Linha 93: | Linha 118: |
uma lista com None retorna-se os elementos originais da seqüência. Sintaxe: |
uma lista com ''None'' retorna-se os elementos originais da seqüência. Sintaxe: {{{ #!python |
Linha 98: | Linha 125: |
Exemplos: |
}}} Exemplos: {{{ #!python |
Linha 103: | Linha 132: |
Linha 106: | Linha 134: |
Linha 109: | Linha 136: |
Linha 112: | Linha 138: |
}}} | |
Linha 115: | Linha 142: |
{{{ #!python |
|
Linha 117: | Linha 146: |
}}} | |
Linha 120: | Linha 150: |
{{{ #!python |
|
Linha 124: | Linha 156: |
Onde M é o tamanho de seq. 3.1.1. Map Completo A forma completa de map admite uma função func (ou None) e um conjunto de seqüencias (seq1, seq2, ..., seqN) como parâmetros. Sintaxe: |
}}} Onde ''M'' é o tamanho de seq. === Forma Completa de Map === A forma completa de map admite uma função ''func'' (ou ''None'') e um conjunto de seqüencias (''seq1, seq2, ..., seqN'') como parâmetros. Sintaxe: {{{ #!python |
Linha 135: | Linha 168: |
Atribuindo-se None ao map este retorna sempre uma tupla de N elementos que |
}}} Atribuindo-se ''None'' ao map este retorna sempre uma tupla de N elementos que |
Linha 141: | Linha 175: |
{{{ #!python |
|
Linha 144: | Linha 179: |
Linha 147: | Linha 181: |
Linha 150: | Linha 183: |
}}} | |
Linha 153: | Linha 187: |
{{{ #!python |
|
Linha 157: | Linha 193: |
Onde M é o tamanho da maior lista entre seq1, seq2, ..., seqN. |
}}} Onde ''M'' é o tamanho da maior lista entre seq1, seq2, ..., seqN. |
Linha 168: | Linha 205: |
{{{ #!python |
|
Linha 170: | Linha 209: |
Linha 173: | Linha 211: |
Linha 178: | Linha 215: |
Oops. 3.2. Reduce A função reduce aplica acumuladamente os ítens de uma seqüência de entrada (da esquerda para a direita) a uma função de dois parâmetros até reduzir esse |
}}} A lista [2, 4, 6] tem um elemento a menos do que [2, 2, 2, 2] e é preenchida com None, por isso o erro. == Reduce == A função ''reduce'' aplica acumuladamente os ítens de uma seqüência de entrada ''seq'' (da esquerda para a direita) a uma função ''func'' de dois parâmetros até reduzir esse |
Linha 186: | Linha 224: |
valor inicial como parâmetro. Sintaxe: |
valor ''inicial'' como parâmetro. Sintaxe: {{{ #!python |
Linha 191: | Linha 230: |
Exemplos: |
}}} Exemplos: {{{ #!python |
Linha 196: | Linha 238: |
Linha 199: | Linha 240: |
3.3. Filter A função filter retorna uma seqüência cujos os valores são os elementos da seqüência de entrada 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 esteja presente o valor de retorno da função é utilizado como valor verdade e apenas os elementos verdadeiros vão fazer parte da seqüência de retorno. Sintaxe: |
}}} == Filter == A função ''filter'' retorna uma seqüência ''seq_ret'' cujos valores são os elementos da seqüê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 seqüência de retorno. Sintaxe: {{{ #!python |
Linha 211: | Linha 254: |
A seqüencia seq_ret tem sempre o mesmo tipo de seq. Exemplos: |
}}} A seqüência ''seq_ret'' tem sempre o mesmo tipo de ''seq''. Exemplos: {{{ #!python |
Linha 218: | Linha 263: |
Linha 221: | Linha 265: |
3.4. Zip A função zip retorna uma seqüência cujos os elementos são tuplas resultantes de cada um dos elementos, de uma ou mais seqüencias de entrada. A seqüência |
>>> filter(lambda s: s > 'a', 'python r0cks!') 'pythonrcks' }}} == Zip == A função ''zip'' retorna uma seqüência ''seq_ret'' cujos elementos são tuplas resultantes de cada um dos elementos de uma ou mais seqüências de entrada ''seq1, seq2, ..., seqN''. A seqüência |
Linha 229: | Linha 276: |
{{{ #!python |
|
Linha 231: | Linha 279: |
Onde seq_ret é obtida através do seguinte logicismo: |
}}} Onde ''seq_ret'' é obtida através do seguinte logicismo: {{{ #!python |
Linha 238: | Linha 289: |
Onde m é o comprimento da menor lista em seq. Exemplos: |
}}} O valor de ''m'' é o comprimento da menor lista em ''seq''. Exemplos: {{{ #!python |
Linha 245: | Linha 299: |
Linha 248: | Linha 301: |
4. Conclusão |
}}} = Exemplos Mais Complexos = |
Linha 254: | Linha 307: |
{{{ #!python |
|
Linha 275: | Linha 330: |
}}} |
Programação Funcional em Python - Rudá Moura <ruda.moura@gmail.com>
Dezembro de 2003. Revisado em 2011.
Resumo:
O objetivo desse artigo é explicar de maneira rápida e de fácil entendimento as características funcionais da Linguagem Python (lambda, map, filter e zip). Entende-se aqui como funcional o paradigma de programação utilizado em linguagens como Lisp e Scheme. O leitor não deve se assustar pois não será necessário contar parênteses para tirar proveito dessas características em Python, (((isto foi uma piada))).
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. Tenha bom senso e cuidado com o seu uso.
Conteúdo
Primeiras Palavras
Uma das vantagens da linguagem Python está no seu rico conjunto de estruturas de dados disponíveis ao programador. Entre essas estruturas destaca-se a lista. A lista é um tipo de dado dinâmico (pode aumentar ou diminuir de tamanho) e mutável (seus elementos individuais podem ser alterados) utilizado para armazenar outros tipos de dados, inclusive outras listas.
O Python provê um conjunto de funções que podem ser aplicados as listas. Pode-se inserir ou remover elementos, classificar/ordenar, tratar a lista como se fosse uma pilha entre outros. É comum também "caminhar" entre os seus elementos, como no exemplo a seguir.
Uma tupla é semelhante a uma lista mas esta é estática (não possui métodos para inserir ou remover elementos) e imutável (os elementos individuais não podem ser alterados). Um exemplo de tupla pode ser um par de elementos, como em (-1, 1) ou um conjunto de pares, como em ( (0, 0, 0), (1, 1, 1), (-1, -1, -1) ).
Uma string, que também é um tipo estático e imutável e pode ter um tratamento análogo ao de uma lista.
Define-se então o termo genérico seqüência para indicar uma tupla, uma string ou uma lista. Note que não existe um tipo seqüência em Python.
A Expressão Lambda
Uma expressão lambda 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.
Exemplos:
Função identidade.
Soma de dois valores.
Note que o resultado é um tipo lambda. Mas como posso obter algo útil, por exemplo, calcular 1+2 com lambda?
Uma maneira de "lembrar" uma expressão lambda é guardá-la em uma variável.
Aparentemente lambda sozinho não tem muita graça ou utilidade, mas nas seções que se seguem faremos melhor uso dela.
As Funções Embutidas Map, Reduce, Filter e Zip
Map
A forma mais simples de se usar o map é aplicando uma função func a uma seqüê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 seqüência.
Sintaxe:
1 map(func ou None, seq) -> lista
Exemplos:
Um exemplo mais interessante com uso da expressão lambda.
Em resumo, se oferecermos uma função ao map, teremos que:
Onde M é o tamanho de seq.
Forma Completa de Map
A forma completa de map admite uma função func (ou None) e um conjunto de seqüencias (seq1, seq2, ..., seqN) como parâmetros.
Sintaxe:
1 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 seqüencias até o tamanho da maior lista, índices maiores que as seqüências são retornados como None.
Exemplos:
Se atribuirmos uma função para map, teremos sempre que:
Onde M é o tamanho da maior lista entre seq1, seq2, ..., seqN.
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 menores que 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.
Exemplos:
1 >>> map(lambda x, y: x*y, [1, 3, 5], [2, 4, 6])
2 [2, 12, 30]
3 >>> map(lambda a, b, x: a*x+b, [1, 3, 5], [2, 4, 8], [0, 0, 0])
4 [2, 4, 8]
5 >>> map(pow, [2, 4, 6], [2, 2, 2, 2])
6 Traceback (most recent call last):
7 File "<stdin>", line 1, in ?
8 TypeError: unsupported operand type(s) for ** or pow(): 'NoneType' and 'int'
A lista [2, 4, 6] tem um elemento a menos do que [2, 2, 2, 2] e é preenchida com None, por isso o erro.
Reduce
A função reduce aplica acumuladamente os ítens de uma seqüê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:
1 reduce(func, seq[, inicial]) -> valor
Exemplos:
Filter
A função filter retorna uma seqüência seq_ret cujos valores são os elementos da seqüê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 seqüência de retorno.
Sintaxe:
1 filter(func ou None, seq) -> seq_ret
A seqüência seq_ret tem sempre o mesmo tipo de seq.
Exemplos:
Zip
A função zip retorna uma seqüência seq_ret cujos elementos são tuplas resultantes de cada um dos elementos de uma ou mais seqüências de entrada seq1, seq2, ..., seqN. A seqüência resultante é sempre truncada ao tamanho da menor seqüência apresentada.
Sintaxe:
1 zip(seq1, seq2, ..., seqN) -> seq_ret
Onde seq_ret é obtida através do seguinte logicismo:
O valor de m é o comprimento da menor lista em seq.
Exemplos:
Exemplos Mais Complexos
Retirado do "Programming FAQ" em python.org, seção 2.12:
1 # Primes < 1000
2 print filter(None,map(lambda y:y*reduce(lambda x,y:x*y!=0,
3 map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,1000)))
4
5 # First 10 Fibonacci numbers
6 print map(lambda x,f=lambda x,f:(x<=1) or (f(x-1,f)+f(x-2,f)): f(x,f),
7 range(10))
8
9 # Mandelbrot set
10 print (lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y,
11 Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM,
12 Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,
13 i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y
14 >=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(
15 64+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(Io-Iu)/Sy),range(Sy
16 ))))(-2.1, 0.7, -1.2, 1.2, 30, 80, 24)
17 # \___ ___ \___ ___ | | |__ lines on screen
18 # V V | |______ columns on screen
19 # | | |__________ maximum of "iterations"
20 # | |_________________ range on y axis
21 # |____________________________ range on x axis
Magia negra? Concordo!