associação pythonbrasil[11] django zope/plone planet Início Logado como (Entrar)

Diferenças para "PrincipiosFuncionais"

Diferenças entre as versões de 4 e 14 (10 versões de distância)
Revisão 4e 2005-03-28 15:18:44
Tamanho: 8354
Comentário:
Revisão 14e 2006-04-13 17:13:30
Tamanho: 11189
Comentário:
Deleções são marcadas assim. Adições são marcadas assim.
Linha 1: Linha 1:
#pragma section-numbers off
Linha 3: Linha 2:
''' #E alguns Linguagismos Pythonicos sobre Funções em geral ;) ''' ''' # E alguns Linguagismos Pythonicos sobre Funções em geral ;) '''

[[TableOfContents]]
Linha 7: Linha 8:
O conceito de funções em programação vem da matemática. Uma função serve para relacionar um conjunto (chamado de domínio) a outro (Imagem). Em programação, o domínio de uma função seriam os valores que pode-se passar como argumentos, e a Imagem é o conjunto dos possíveis valores de retorno. Para cada elemento no conjunto Domínio, deve haver apenas um elemento correspondente no conjunto imagem. Em programação funcional (e na matemática) esse é o princípio de idempotência, ou seja, para determinado valor de argumento só há uma possibilidade de retorno a cada vez que se passar um determinado valor como argumento.

Esse conceito foi introduzido na programação no final dos anos 50 pela linguagem Lisp, numa epoca em que a linguagem de mais alto nível que existia era o primeiro Fortran. Muitas linguagens desde então sofreram algum tipo de influência de Lisp e seus idiomas, direta ou indiretamente. Inclusive Python, que, por exemplo, tem um '''tipo''' função.
O conceito de funções em programação vem da matemática. Uma função serve para relacionar um conjunto (chamado de domínio) a outro (Imagem). Em programação, o domínio de uma função seriam os valores que pode-se passar como argumentos, e a Imagem é o conjunto dos possíveis valores de retorno. Para cada elemento no conjunto Domínio, deve haver apenas um elemento correspondente no conjunto imagem. Em programação funcional (e na matemática) esse é o princípio de idempotência, ou seja, para determinado valor de argumento só há uma possibilidade de retorno a cada vez que se passar um este valor como argumento.

Esse conceito foi introduzido na programação no final dos anos 50 pela linguagem Lisp, numa época em que a linguagem de mais alto nível que existia era o primeiro Fortran. Muitas linguagens desde então sofreram algum tipo de influência de Lisp e seus idiomas, direta ou indiretamente. Inclusive Python, que, por exemplo, tem um '''tipo''' função.
Linha 15: Linha 16:
As funções em Python são definidas atravez da palavra chave def. Sua sintaxe é a seguinte: Antes de explorar os conceitos funcionais, vamos deixar os mecanismos de PYthon para criação e uso de funções bem claros.

As funções
em Python são definidas através da palavra chave def. Sua sintaxe é a seguinte:
Linha 27: Linha 30:
#!python
def foo(a=1, b=2):
    return a+b
}}}
''Na função foo, a e b são argumentos não obrigatorios''

{{{
#!python
def bar(a, b):
    return a+b
}}}
''Na função bar, a e b são argumentos obrigatorios''

Em Python, ao contrário de algumas linguagens que não lhe permitem passar uma matriz como argumento, não há restrições quanto a passar uma sequencia (strings, listas, tuplas, unicodes) como argumento.
{{{
#!python
def spam(x=[1, 2, 3]):
    if type(x) == list:
        return "É possivel passar uma lista como argumento em Python!"
}}}

Você também pode definir um argumento precedido de um * (asterisco), para "capturar" o resto dos argumentos numa tupla (Ficando uma função com número de argumentos variavel).
>>> def func(a,b='mundo',c='!'):
... print a, b, c
...
>>> func('olá')
olá mundo !
>>> func('olá', 'pessoal')
olá pessoal !
>>> func()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: func() takes at least 1 argument (0 given)
}}}
Quando houver mais de um argumento opcional na função e você quiser especificar apenas um ou mais deles, você pode chamar a função dizendo qual argumento você quer especificar:

{{{
>>> func('adeus',c='?')
adeus mundo ?
}}}

É possível declarar um argumento para pegar os parâmetros extras passados à função, precedendo-o com um asterisco:
{{{
>>> def func(a,b='b',*args,**kwargs):
... print 'a = %s\nb = %s\nargs = %s\nkwargs = %s' % (a,b,args,kwargs)
...
>>> func('a','c','d','e',par1='f',par2='g')
a = a
b = c
args = ('d', 'e')
kwargs = {'par2': 'g', 'par1': 'f'}
}}}
Note que foram declarados dois argumentos precedidos por asteriscos. O primeiro, precedido por um asterisco, irá receber os parâmetros extras passados em forma de tupla, e o segundo irá receber os parâmetros extras ''nomeados'' em forma de dicionário. Experimente outras variações no shell do python.
Linha 58: Linha 71:
Você pode, ainda, usar ** antes de um argumento na definição da função. #Explicar esse truque! preciso de uma explicação melhor!
{{{
<exemplos>
}}}

Você pode ainda se aproveitar do polimorfismo da linguagem e permitir que sejam passados "tipos afins", como tipos que podem ser usados numa iteração, e não só um tipo, como lista por exemplo, aumentado a possibilidade de reuso do codigo.
Ao contrário de algumas linguagens que não lhe permitem passar uma matriz como argumento, Python não faz restrições quanto a passar uma sequência (strings, listas, tuplas, unicodes) como argumento.
{{{
#!python
def spam(
x=[1, 2, 3]):
    if isinstance(x, list):
        return "É possível passar uma lista como argumento em Python!"

}}}

Você pode ainda se aproveitar do polimorfismo da linguagem e permitir que sejam passados "tipos afins", como tipos que podem ser usados numa iteração, e não só um tipo, como lista por exemplo, aumentado a possibilidade de reuso do código.
Linha 96: Linha 112:
=== "Side-Effects" === Python permite que sejam criadas funções HighOrder, ou seja, uma funções que recebem como argumento ou retornam outras funções. Isso é especialmente interessante de ser usado em conjunto com @Decorators.
{{{
#!python
}}}


== Chamadas de Função ==

Na hora de chamar uma função, você pode passar como argumento outra chamada de função, e será passado o valor de retorno dessa. Assim os valores fluirão de uma função para outra, sem necessidade uma variável de "transporte".
{{{
#!python
#Exemplo mais inútil impossível, mas espero que você pegue a idéia :)
range(sum([0, 1, 2]))
}}}

Entre outras coisas "pensar funcionalmente" pode ser definido assim: projetar algoritmos onde os valores fluem do retorno de uma função para a chamada de outra.

Você pode usar um asterisco antes de um argumento na chamada da função para passar os argumentos da função atravez de uma lista.
{{{
#!python
#lembra do nosso cdr?
cdr(*range(5))
}}}

== "Side-Effects" ==
Linha 106: Linha 146:
side_effect() our_double_a()
Linha 111: Linha 151:
#!python
Linha 117: Linha 158:
#Se o que quisermos e apena imprimir o valor de retorno... #Se o que quisermos e apenas imprimir o valor de retorno...
Linha 122: Linha 163:
Evite Side-Effects em suas funções. Sua função fica mais dificil de se adivinhar o que faz do que se você retornasse um valor que fosse explicitamente atribuido a um nome. Procure usar sempre os argumentos e os returns. Seguindo essa regra suas funções serão inclusive mais uteis em outras ocasiõea (maior reaproveitamento de codigo)

Por exemplo, na nossa funcao "our_double_a" e dificil de imaginar que ela alteraria o valor de x. Alem disso, ela fica limitada a isso, alterar o valor do nome x.Compare com a funcao our_double_b: fica claro quando eu estou alterando o valor de x ou nao.
Evite Side-Effects em suas funções. Sua função fica mais difícil de se adivinhar o que faz do que se você retornasse um valor que pudesse ser explicitamente atribuído a um nome. Procure usar sempre os argumentos e os returns. Seguindo essa regra suas funções serão inclusive mais uteis em outras ocasiões (maior reaproveitamento de código)

Por exemplo, na nossa função "our_double_a" é difícil de imaginar que ela alteraria o valor de x. Além disso, ela fica limitada a isso: alterar o valor do nome x. Compare com a função our_double_b: fica claro quando eu estou alterando o valor de x ou não.
Linha 131: Linha 172:
=== Recursão ===

Muitas pessoas acham extremamente complicado aplicar o conceito de recursão, muitos alunos de programação não conseguem desenvolver algoritmos recursivos sem gastar **muito** grafite e papel antes. Muitos programadores acostumados com paradgmas extruturados tamb tem essa dificuldade, A maioria dos programadores evitam implementações recursivas de seus algoritmos, por motivos de performance também, mas muitas vezes nem percebemos que um codigo poderia usar recursão.
Certas linguagens funcionais, como Scheme, preveem até mesmo que seus interpretadores tenham algum tipo de otimização de recursão.
Pergunte a um estudante dedicado de programação "Quando colocar um trecho de codigo em um bloco separado?" e ele dirá algo como "Quando o codigo se repete". Mas quando o codigo se repete sucessivamente, normalmente usamos '''for''' ou '''while'''. Quando não houverem grandes problemas para a performance, a recursão pode valer a pena se trousser um melhor estilo.
== Recursão ==

Uma função que chama a si mesma é uma função recursiva.

Muitas pessoas acham extremamente complicado aplicar o conceito de recursão, muitos alunos de programação não conseguem desenvolver algoritmos recursivos sem gastar **muito** grafite e papel antes. Muitos programadores acostumados com paradigmas estruturados também tem essa dificuldade, A maioria dos programadores evitam implementações recursivas de seus algoritmos, por motivos de performance também, mas muitas vezes nem percebemos que um código poderia usar recursão.

Certas linguagens funcionais, como Scheme, prevêem até mesmo que seus interpretadores tenham algum tipo de otimização de recursão.

Pergunte a um estudante dedicado de programação "Quando colocar um trecho de código em um bloco separado?" e ele dirá algo como "Quando o código se repete". Mas quando o código se repete sucessivamente, normalmente usamos '''for''' ou '''while'''. Quando não houverem grandes problemas para a performance, a recursão pode valer a pena se trouxer um melhor estilo.
Linha 145: Linha 191:
== Chamadas de Função ==

Na hora de chamar uma função, você pode passar como argumento outra chamada de função, e será passado o valor de retorno dessa. Assim os valores fluirão de uma função para outra, sem necessidade uma variavel de "tranporte".
{{{
#!python
#Exemplo mais inutil impossivel, mas espero que você pegue a ideia :)
range(sum([0, 1, 2]))
}}}

Entre outras coisas "pensar funcionalmente" pode ser definido assim: projetar algoritmos onde os valores fluem do retorno de uma função para a chamada de outra.

Voce pode usar um asterisco antes de um argumento na chamada da função para passar os argumentos da função atravez de uma lista.
{{{
#!python
#lembra do nosso cdr?
cdr(*range(5))
}}}

=== Estilo ===
No livro capitulo 2.7 [http://www.paulgraham.com/lib/paulgraham/acl2.txt ANSI Common Lisp], ''Recursion'', PaulGraham diz: (livre tradução)

''
(...)
Muitas pessoas pessoas acham difícil a recurção no inicio. Muita dessa dificuldade vem do uso de uma metafora enganosa para funções. Há uma tendencia a pensar em funções como um tipo de maquinas. Matéria prima entra como os parâmetros; Algumas tarefas são repassadas para outras funções; finalmente o produto acabado é montado e entregue como o valor de retorno. se nós usarmos essa metáfora para funções, a recursão se torna um paradoxo. Como uma maquina pode enviar tarefas para ela mesma? Ela já esta ocupada.''

''Uma melhor metáfora para a função seria pensar nela como um processo que se passa. Recursão é natural em um processo(...)''

== Closures ==

Python suporta Closures (ou [http://en.wikipedia.org/wiki/Closure_%28computer_science%29 lexical closures]) desde a versão 2.0, atravéz dos recurso de '''Nested Scopes'''.

Exemplo:

{{{#!python
<exemplo>
}}}

== Estilo ==
Linha 181: Linha 227:
== Na Wiki: == == Na Wiki ==
Linha 185: Linha 231:

UsandoGenerators
Linha 191: Linha 239:
[http://c2.com/cgi/wiki?HigherOrderFunction C2 Wiki - Higher Order Function]

[http://en.wikipedia.org/wiki/Python_programming_language#Functional_programming Python na Wikipedia - Seção Functional Programming]
Linha 193: Linha 245:
 * Adicionar mais exemplos! (de preferencia tirados do UselessPython !!)
 * Links para essays do PaulGraham onde ele cita Python
 *
Mais exemplos, mais exemplos!!! De preferencia, alguns uteis ou interessantes :)
 * Adicionar mais exemplos! (de preferência tirados do UselessPython !!)
 * Mais exemplos, mais exemplos!!! De preferência, alguns úteis ou interessantes :)
 * Mais sobre HighOrder functions, quem sabe uma seção própria?
 * Concluir a seção sobre ''Closures'', com exemplos.
 * Citar e exemplificar o {{{lambda}}}
 * Uma seção somente com ''Exemplos Práticos''.
Linha 197: Linha 252:
Linha 199: Linha 255:

----
''Sugestão:'' Esta página fala na maior parte de particularidades das funções em python. Poderíamos mover este conteúdo para outra página (que poderia ser usada no NossoLivro) e deixar aqui apenas as coisas relativas à programação funcional. LuizCarlosGeron

Principios da Programação Funcional em Python

# E alguns Linguagismos Pythonicos sobre Funções em geral ;)

TableOfContents

Introdução

O conceito de funções em programação vem da matemática. Uma função serve para relacionar um conjunto (chamado de domínio) a outro (Imagem). Em programação, o domínio de uma função seriam os valores que pode-se passar como argumentos, e a Imagem é o conjunto dos possíveis valores de retorno. Para cada elemento no conjunto Domínio, deve haver apenas um elemento correspondente no conjunto imagem. Em programação funcional (e na matemática) esse é o princípio de idempotência, ou seja, para determinado valor de argumento só há uma possibilidade de retorno a cada vez que se passar um este valor como argumento.

Esse conceito foi introduzido na programação no final dos anos 50 pela linguagem Lisp, numa época em que a linguagem de mais alto nível que existia era o primeiro Fortran. Muitas linguagens desde então sofreram algum tipo de influência de Lisp e seus idiomas, direta ou indiretamente. Inclusive Python, que, por exemplo, tem um tipo função.

Segundo o artigo da Wikipedia [http://en.wikipedia.org/wiki/Python_programming_language#Philosophy Python programming language - seção "Philosophy"], Python é uma linguagem multiparadigma. Então por que não aprender mais um? :)

Definindo Funções em Python

Antes de explorar os conceitos funcionais, vamos deixar os mecanismos de PYthon para criação e uso de funções bem claros.

As funções em Python são definidas através da palavra chave def. Sua sintaxe é a seguinte:

   1 def NomeDaFuncao(arg1, arg2, argn):
   2     <codigo>
   3     return NomeDoObjetoARetornar

Argumentos

Em Python, os argumentos podem ou não ter um valor inicial. Quando se dá um valor inicial na definição, não é obrigatório passar nenhum valor para esse argumento na chamada da função.

>>> def func(a,b='mundo',c='!'):
...  print a, b, c
...
>>> func('olá')
olá mundo !
>>> func('olá', 'pessoal')
olá pessoal !
>>> func()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: func() takes at least 1 argument (0 given)

Quando houver mais de um argumento opcional na função e você quiser especificar apenas um ou mais deles, você pode chamar a função dizendo qual argumento você quer especificar:

>>> func('adeus',c='?')
adeus mundo ?

É possível declarar um argumento para pegar os parâmetros extras passados à função, precedendo-o com um asterisco:

>>> def func(a,b='b',*args,**kwargs):
...  print 'a = %s\nb = %s\nargs = %s\nkwargs = %s' % (a,b,args,kwargs)
...
>>> func('a','c','d','e',par1='f',par2='g')
a = a
b = c
args = ('d', 'e')
kwargs = {'par2': 'g', 'par1': 'f'}

Note que foram declarados dois argumentos precedidos por asteriscos. O primeiro, precedido por um asterisco, irá receber os parâmetros extras passados em forma de tupla, e o segundo irá receber os parâmetros extras nomeados em forma de dicionário. Experimente outras variações no shell do python.

   1 # Esta função é levemente semelhante ao "cdr" do lisp, mas o cdr do Lisp recebe uma lista
   2 # Esta recebe o que seriam os elementos da lista
   3 def cdr(arg1, *argN):
   4     "Retorna tupla com os argumentos, excluindo o primeiro"
   5     return argN

Ao contrário de algumas linguagens que não lhe permitem passar uma matriz como argumento, Python não faz restrições quanto a passar uma sequência (strings, listas, tuplas, unicodes) como argumento.

   1 def spam(x=[1, 2, 3]):
   2     if isinstance(x, list):
   3         return "É possível passar uma lista como argumento em Python!"

Você pode ainda se aproveitar do polimorfismo da linguagem e permitir que sejam passados "tipos afins", como tipos que podem ser usados numa iteração, e não só um tipo, como lista por exemplo, aumentado a possibilidade de reuso do código.

Retornando valores

Você também pode retornar qualquer objeto (até mesmo uma função) de uma função.

   1 def RetornaFuncao(x=type):
   2     return x
   3 
   4 RetornaFuncao()(list)

Nesse exemplo, a ultima linha deve retornar <type 'type'>, por que list é um tipo

Sua função pode ainda ter varias vezes a palavra return.

   1 def isDead(parrot):
   2     "Retorna True se parrot avaliar como False"
   3     if not obj:
   4         return True
   5     else:
   6         return False

Caso existam returns alinhados, no mesmo bloco, apenas o primeiro funcionará:

   1 def DoisReturns(x, y):
   2     return x
   3     return y

Python permite que sejam criadas funções HighOrder, ou seja, uma funções que recebem como argumento ou retornam outras funções. Isso é especialmente interessante de ser usado em conjunto com @Decorators.

   1 

Chamadas de Função

Na hora de chamar uma função, você pode passar como argumento outra chamada de função, e será passado o valor de retorno dessa. Assim os valores fluirão de uma função para outra, sem necessidade uma variável de "transporte".

   1 #Exemplo mais inútil impossível, mas espero que você pegue a idéia :)
   2 range(sum([0, 1, 2]))

Entre outras coisas "pensar funcionalmente" pode ser definido assim: projetar algoritmos onde os valores fluem do retorno de uma função para a chamada de outra.

Você pode usar um asterisco antes de um argumento na chamada da função para passar os argumentos da função atravez de uma lista.

   1 #lembra do nosso cdr?
   2 cdr(*range(5))

"Side-Effects"

"Side-Effect", ou algo como 'efeito colateral', é um termo usado para indicar que uma função faz uma operação "destrutiva" , ou seja, ela altera, por exemplo, o valor de um objeto global, ou faz alguma operação de IO.

   1 x = 1
   2 def our_double_a():
   3     global x
   4     x += x
   5 
   6 our_double_a()
   7 print x
   8 #Isso deve imprimir 2 n tela

   1 def our_double_b(y):
   2     y += y
   3     return y
   4 #Se o que quisermos e apenas alterar o valor de x...
   5 x = 1
   6 x = our_double_b(x)
   7 #Se o que quisermos e apenas imprimir o valor de retorno...
   8 x = 1
   9 print our_double_b(x)

Evite Side-Effects em suas funções. Sua função fica mais difícil de se adivinhar o que faz do que se você retornasse um valor que pudesse ser explicitamente atribuído a um nome. Procure usar sempre os argumentos e os returns. Seguindo essa regra suas funções serão inclusive mais uteis em outras ocasiões (maior reaproveitamento de código)

Por exemplo, na nossa função "our_double_a" é difícil de imaginar que ela alteraria o valor de x. Além disso, ela fica limitada a isso: alterar o valor do nome x. Compare com a função our_double_b: fica claro quando eu estou alterando o valor de x ou não.

Se você realmente pretende fazer uma função que tem Side-Effects, deixe isso bem claro no nome (adicionando um prefixo "set" e o que ele "seta", com "setName", por exemplo) e na docstring da função.

<exemplo>

Recursão

Uma função que chama a si mesma é uma função recursiva.

Muitas pessoas acham extremamente complicado aplicar o conceito de recursão, muitos alunos de programação não conseguem desenvolver algoritmos recursivos sem gastar **muito** grafite e papel antes. Muitos programadores acostumados com paradigmas estruturados também tem essa dificuldade, A maioria dos programadores evitam implementações recursivas de seus algoritmos, por motivos de performance também, mas muitas vezes nem percebemos que um código poderia usar recursão.

Certas linguagens funcionais, como Scheme, prevêem até mesmo que seus interpretadores tenham algum tipo de otimização de recursão.

Pergunte a um estudante dedicado de programação "Quando colocar um trecho de código em um bloco separado?" e ele dirá algo como "Quando o código se repete". Mas quando o código se repete sucessivamente, normalmente usamos for ou while. Quando não houverem grandes problemas para a performance, a recursão pode valer a pena se trouxer um melhor estilo.

   1 def factorial(x):
   2     if x == 0:
   3         return 1
   4     else:
   5         return x * factorial(x-1)

No livro capitulo 2.7 [http://www.paulgraham.com/lib/paulgraham/acl2.txt ANSI Common Lisp], Recursion, PaulGraham diz: (livre tradução)

(...) Muitas pessoas pessoas acham difícil a recurção no inicio. Muita dessa dificuldade vem do uso de uma metafora enganosa para funções. Há uma tendencia a pensar em funções como um tipo de maquinas. Matéria prima entra como os parâmetros; Algumas tarefas são repassadas para outras funções; finalmente o produto acabado é montado e entregue como o valor de retorno. se nós usarmos essa metáfora para funções, a recursão se torna um paradoxo. Como uma maquina pode enviar tarefas para ela mesma? Ela já esta ocupada.

Uma melhor metáfora para a função seria pensar nela como um processo que se passa. Recursão é natural em um processo(...)

Closures

Python suporta Closures (ou [http://en.wikipedia.org/wiki/Closure_%28computer_science%29 lexical closures]) desde a versão 2.0, atravéz dos recurso de Nested Scopes.

Exemplo:

   1 <exemplo>

Estilo

Procure usar o caracter \ para quebrar a linha e evitar linhas muito longas e ilegiveis. Exemplo:

   1 function1(\
   2           function11("foo"),\
   3           function12(\
   4                      function121(1, "bar"),\
   5                      function122("foobar")),\
   6           function13(84))

Conclusão

Links

Na Wiki

PythonFuncional

ProgramacaoFuncional

UsandoGenerators

No resto da Web

[http://diveintopython.org/functional_programming/index.html Dive into Python - Chapter 16. Functional Programming]

[http://en.wikipedia.org/wiki/Python_programming_language#Functional_programming Wikipedia - Python programming language - Functional programming]

[http://c2.com/cgi/wiki?HigherOrderFunction C2 Wiki - Higher Order Function]

[http://en.wikipedia.org/wiki/Python_programming_language#Functional_programming Python na Wikipedia - Seção Functional Programming]

Por fazer:

  • Adicionar Links para trechos afins do DiveIntoPython, Thinking Like a Computer Scientist, etc

  • Adicionar mais exemplos! (de preferência tirados do UselessPython !!)

  • Mais exemplos, mais exemplos!!! De preferência, alguns úteis ou interessantes :)

  • Mais sobre HighOrder functions, quem sabe uma seção própria?

  • Concluir a seção sobre Closures, com exemplos.

  • Citar e exemplificar o lambda

  • Uma seção somente com Exemplos Práticos.

  • Uma Conclusão


EduardoDeOliveiraPadoan


Sugestão: Esta página fala na maior parte de particularidades das funções em python. Poderíamos mover este conteúdo para outra página (que poderia ser usada no NossoLivro) e deixar aqui apenas as coisas relativas à programação funcional. LuizCarlosGeron