Qual a finalidade de declarar uma função dentro de uma função? – python python-3.x funções

Pergunta:


Em Python é possível declarar uma função dentro de outra função, como é mostrado no código a seguir.

def foo(palavra=None):
    print(palavra)
    def bar(outra_palavra=None):
        print(outra_palavra)


if __name__ == '__main__':
    foo(palavra='metodo main')

Porém qual é a finalidade prática de tal flexibilidade da linguagem? Em qual cenário fazer uso de tal ferramenta possibilita um ganho?

Autor da pergunta Bruno Camargo

Maniero

Um motivo é o encapsulamento. Se a função interna será chamada só por esta função não tem porque colocar fora. Colocando dentro garante que ninguém mais pode chamar.

Uma coisa que eu noto é que as pessoas aprendem programar sem entender o que está fazendo e uma das coisas que as pessoas não entendem é a função da função (trocadilho intencional 🙂 ). Funções servem para abstrair algoritmos. Servem para indicar com mais claridade e organização ao que está fazendo ao mesmo tempo que cria uma forma canônica daquela operação., um conceito conhecido como DRY.

É possível que algo que a função externa faz se repita e faz sentido abstrair em uma função. Como só ela precisa disto é melhor não expor para outras partes. Quanto menos expor menos preocupação tem e mais fácil de dar manutenção.

Uma característica legal é que você pode retornar a própria função, ou seja seu método prepara a função e entrega para quem precise usar interna. Isto é feito com uma técnica chamada de função anônima. Assim você cria uma função nomeada e usa seu nome como se fosse uma variável, então a função não é executada e sim repassada como se fosse um dado (isto é otimizado através de ponteiro). Algo assim:

def GeraCondicao(valor):
    def Condicao(item):
        return item > valor
    return Condicao

condicao = GeraCondicao(5)
for i in range(0, 10):
    if condicao(i)
        print i

Imprimirá de 6 à 10.

No caso usei uma closure (outra definição) já que um dado da função externa foi capturada pela função interna

Obviamente que pode gerar essa condição de várias formas, pode chamar outras funções que criam funções anônimas e compor do jeito que precisar.

Claro que não precisa nem retornar, pode só passar para outra função que está chamando ali mesmo onde a função interna foi criada.

Tem alguns usos possíveis. Os principais são esses dois:

fábrica de funções

Esse talvez seja o uso principal. Como funções são objetos de primeira classe em em Python, cada vez que uma função que contém outras é chamada, as funções declaradas internamente são recriadas (Mas não compiladas de novo: o bytecode das funções aninhadas é criado em um passo anterior). Elas terão acesso as variáveis da função externa, que serão também separadas a cada chamada (que cria um “closure”).

Acho que um dos usos mais comuns é na quando se escreve um decorador em Python. Decoradores em Python são funções que recebem como único parâmetro uma outra função. Eles retornam um objeto chamável, em geral uma função também, que pode executar algum código antes e depois da chamada da função original. Então o código de um decorador simples fica assim:

def decorator(func):
    def wrapper(*args, **kwargs):
        # código anterior a chamada original
        ...
        result = func(*args, **kwargs)
        # código posterior a chamada original
        ...
        return result
    return wrapper


@decorator
def minha_funcao():
   ...

Nesse caso, cada vez que “minha_funcao” for chamada, o que será executado será a função wrapper declada dentro do decorator – mas uma função wrapper em que a variável func vai ser exatamente o parâmetro da função decorator que recebe minha_funcao original como parâmetro.

Se o decorador for usado mais de uma vez, func receberá as outras funções decoradas, e será criada uma função wrapper distinta para cada uso.

É interessante ter em mente que uma função aninhada pode acessar as variáveis das funções externas, e, em Python 3, até atribuir novos valores a essas variáveis , com o uso da declaração nonlocal (em Python 2, as variáveis externas eram somente de leitura).

legibilidade

Python deliberadamente restringe as funções do tipo “lambda” a serem apenas uma expressão. Em geral, funções do tipo “lambda” são usadas como parâmetros para outras funções, por exemplo, para obter a chave de ordenação de uma sequência no método sort, ou um comando a ser executado quando é clicado um botão de um programa gráfico.

Se a função a ser passada como parâmetro for um pouco mais complexa, e precisar ter variáveis, ifs, etc… já vale a pena declara-la como uma função independente, aninhada.

Nada impediria que impediria que essa função aninhada estivesse fora do código principal – mas a declaração aninhada permite que ela esteja próxima do ponto onde é usada uma única vez – e se aquela lógica estiver relacionada com a função de fora.

Não confunda métodos de classe com funções.

Não é possível que um Método de Classe contenha um outro Método de Classe declarado dentro do seu escopo.

Métodos de Classe estão sempre associados a Classes. Só podem ser declarados dentro de uma Classe. Métodos de Classe só podem ser chamados a partir da especificação do nome de sua Classe (método estáticos) e/ou a partir de uma instância de sua Classe.

Já uma função é independente, elas podem ser declaradas dentro de outras funções bem como dentro de Métodos de Classe. Repare que Funções declaradas dentro de Classes, na verdade, são Métodos de Classe!

Permitir que funções sejam declaradas dentro do escopo de outras funções e/ou Métodos de Classe flexibiliza muito o encapsulamento.

Repare que até mesmo programas escritos de forma estruturada podem encapsular suas funções, publicando para o escopo de fora (o cliente) somente as funções que realmente importam.

No seu exemplo, lê-se que: A função foo() encapsula a função bar(); Não é interessante que função bar() seja visível pelo o escopo de fora; A função bar() é intimamente acoplada a função foo();Ninguém fora do escopo de foo() é capaz de chamar bar().

O encapsulamento, se aplicado de forma adequada, aumenta muito a legibilidade e o reaproveitamento do código, que por sua vez facilita muito seu desenvolvimento e manutenção.

Fonte

Related Posts:

Qual a diferença entre AppCompatActivity e Activity? – android android-activity
Pergunta: Qual a diferença da AppCompatActivity para Activity ? A partir de qual versão a AppCompatActivity foi adicionada ao Android? Autor da pergunta Luhhh A diferença reside ...
Como abreviar palavras em PHP? – php string
Pergunta: Possuo informações comuns como nome de pessoas e endereços, e preciso que elas contenham no máximo 30 caracteres sem cortar palavras. Exemplo: 'Avenida Natalino João Brescansin' ...
Qual é a finalidade de um parêntese vazio numa declaração Lambda? – c# expressões-lambda característica-linguagem
Pergunta: Criei um exemplo de uma declaração Lambda sem argumentos, entretanto, estou com duvidas referente a omissão do parêntese vazio () na declaração. Veja o exemplo: class ...
Boas práticas para URI em API RESTful – api rest restful
Pergunta: Estou com dúvida em relação às URIs de alguns recursos da api que estou desenvolvendo. Tenho os recursos projetos e atividades com relação 1-N, ...
Dúvidas sobre a integração do MySQL com Java – java mysql netbeans
Pergunta: Estou criando um sistema no NetBeans, utilizando a linguagem Java e o banco de dados MySQL. Escrevi o seguinte código para realizar a conexão ...
Qual é a finalidade da pasta Model do framework Inphinit? – php inphinit
Pergunta: No Inphinit micro-framework existe a pasta Model que fica dentro da pasta application, e nela é onde ficam as classes, mas eu estou muito ...
Uso do ‘@’ em variáveis – javascript typescript coffeescript
Pergunta: Vejo em algumas linguagens que compilam para javascript, como TypeScript e CoffeeScript, o uso do @ em variáveis, como também, casos em que o ...
Qual tamanho máximo um arquivo JSON pode ter? – json arquivo
Pergunta: Vou dar um exemplo para conseguir explicar minha duvida: Preciso recuperar informação de imagens vindas de uma API, esse banco de imagens me retorna JSON's ...
O que é Teste de Regressão? – terminologia engenharia-de-software testes
Pergunta: Na matéria de Teste de Software o professor abordou um termo chamado Teste de Regressão, isto dentro da disciplina de teste de software. Sendo ...
O que é um construtor da linguagem? – php característica-linguagem
Pergunta: Em PHP, já li e ouvi várias vezes a respeito dos Construtores da Linguagem. Os casos que sempre ouvi falar deles foi em casos ...
Função intrínseca para converter numérico para string – cobol
Pergunta: Estou a tentar saber se existe alguma função intrínseca do COBOL para converter um data numérico para string sem precisar usar a cláusula REDEFINES: ( ...
Porque usar implements? – java android
Pergunta: Qual a diferença entre usar btn.setOnClickListener(new OnClickListener() { e public class MainActivity extends Activity implements OnClickListener{ Estive fazendo um curso de Android e meu professor falou que ...
O que é XHTML e quando deve ser usado? – html xml xhtml
Pergunta: O que eu sei é que o XHTML precisa ser XML válido. Isso implica, por exemplo, que todas as tags precisam ser fechadas. Por ...
Uma placa aceleradora de vídeo pode melhorar o desempenho não-gráfico? [fechada] – desempenho
Pergunta: Para desenvolver em Ruby on Rails, eu utilizo aqui uma máquina virtual do VirtualBox com Ubuntu Server 14.04 sem interface gráfica instalada. Recentemente descobri uma ...
Concat() VS Union() – c# .net
Pergunta: Qual a diferença entre Concat() e Union() ? Quando usar Concat() e quando usar Union() ? Somente pode ser usado em list ? ...

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *