--- title: Nested Functions in Python localeTitle: Funções aninhadas em Python --- ### Namespaces Os parâmetros de uma função, mais quaisquer variáveis ​​vinculadas (por atribuição ou por outras instruções de ligação, como def) no corpo da função, compõem o espaço de nomes local da função, também conhecido como escopo local. Cada uma dessas variáveis ​​é conhecida como uma variável local da função. Variáveis ​​que não são locais são conhecidas como variáveis ​​globais (na ausência de definições de funções aninhadas, as quais discutiremos em breve). Variáveis ​​globais são atributos do objeto de módulo, como abordado em "Atributos de objetos de módulo" na página 140. Sempre que a variável local de uma função tiver o mesmo nome de uma variável global, esse nome, dentro do corpo da função, refere-se à variável local, não o global. Expressamos isso dizendo que a variável local oculta a variável global com o mesmo nome em todo o corpo da função. ### A declaração global Por padrão, qualquer variável vinculada a um corpo de função é uma variável local da função. Se uma função precisar religar algumas variáveis ​​globais, o primeiro declaração da função deve ser: identificadores globais onde identificadores é um ou mais identificadores separados por vírgulas (,). Os identificadores listados em uma declaração global referem-se às variáveis ​​globais (ou seja, atributos do objeto do módulo) que a função precisa ser religada. Por exemplo, o contador de funções que vimos em "Outros atributos de objetos de função" na página 73 poderia ser implementado usando uma variável global e global, em vez de um atributo do objeto de função: \_count = 0 contador de def (): \_count global \_count + = 1 return \_count Sem a declaração global, a função de contador levantaria uma exceção UnboundLocal-Error porque \_count seria, então, uma variável local não inicializada (não acoplada). Embora a declaração global permita esse tipo de programação, esse estilo é frequentemente deselegante e desaconselhável. Como mencionei anteriormente, quando você deseja agrupar algum estado e algum comportamento, os mecanismos orientados a objeto abordados no Capítulo 5 são geralmente os melhores. Não use global se o corpo da função apenas usar uma variável global (incluindo a mutação do objeto ligado a essa variável se o objeto for mutável). Use uma declaração global somente se o corpo da função religar uma variável global (geralmente atribuindo ao nome da variável). Por uma questão de estilo, não use global a menos que seja estritamente necessário, pois sua presença fará com que os leitores do seu programa assumam que a declaração está lá para algum propósito útil. Em particular, nunca use global, exceto como a primeira instrução em um corpo de função. {mospagebreak title = Funções aninhadas e escopos aninhados} Uma declaração def dentro de um corpo de função define uma função aninhada, e a função cujo corpo inclui o def é conhecida como uma função externa à função aninhada. Código no corpo de uma função aninhada pode acessar (mas não religar) variáveis ​​locais de uma função externa, também conhecidas como variáveis ​​livres da função aninhada. A maneira mais simples de permitir que uma função aninhada acesse um valor geralmente não é confiar em escopos aninhados, mas sim passar explicitamente esse valor como um dos argumentos da função. Se necessário, o valor do argumento pode ser vinculado quando a função aninhada é definida usando o valor como padrão para um argumento opcional. Por exemplo: def percent1 (a, b, c): def pc (x, total = a + b + c): retorno (x \* 100,0) / total print "Porcentagens são:", pc (a), pc (b), pc (c) Aqui está a mesma funcionalidade usando escopos aninhados: def percent2 (a, b, c): def pc (x): retorno (x \* 100,0) / (a ​​+ b + c) print "Porcentagens são:", pc (a), pc (b), pc (c) Neste caso específico, o percent1 tem uma pequena vantagem: o cálculo de um + b + c acontece apenas uma vez, enquanto o pc da função interna do percent22 repete o cálculo três vezes. No entanto, se a função externa religar suas variáveis ​​locais entre as chamadas para a função aninhada, a repetição da computação poderá ser necessária. Portanto, é aconselhável estar ciente de ambas as abordagens e escolher o mais apropriado caso a caso. Uma função aninhada que acessa valores de variáveis ​​locais externas também é conhecida como encerramento. O exemplo a seguir mostra como construir um encerramento: def make\_adder (augend): def add (addend): return addend + augend retorno add Os fechamentos são uma exceção à regra geral de que os mecanismos orientados a objeto abordados no Capítulo 5 são a melhor maneira de agrupar dados e códigos. Quando você precisa especificamente construir objetos selecionáveis, com alguns parâmetros fixos no tempo de construção do objeto, os encerramentos podem ser mais simples e mais efetivos do que as classes. Por exemplo, o resultado de make\_adder (7) é uma função que aceita um único argumento e adiciona 7 a esse argumento. Uma função externa que retorna um encerramento é uma "fábrica" ​​para membros de uma família de funções distinguida por alguns parâmetros, como o valor do argumento augend no exemplo anterior, e pode frequentemente ajudá-lo a evitar a duplicação de código. ### Expressões de lambda Se um corpo da função for uma instrução de expressão de retorno única, você poderá optar por substituir a função pelo formulário de expressão lambda especial: Parâmetros lambda: expression Uma expressão lambda é o equivalente anônimo de uma função normal cujo corpo é uma única instrução de retorno. Observe que a sintaxe lambda não usa a palavra-chave return. Você pode usar uma expressão lambda sempre que puder usar uma referência a uma função. O lambda às vezes pode ser útil quando você deseja usar uma função simples como argumento ou valor de retorno. Aqui está um exemplo que usa uma expressão lambda como um argumento para a função de filtro interna (coberta no filtro na página 161): aList = \[1, 2, 3, 4, 5, 6, 7, 8, 9\] baixo = 3 alta = 7 filtro (lambda x, l = baixo, h = alto: h> x> l, aList) # retorna: \[4, 5, 6\] Como alternativa, você sempre pode usar uma instrução def local que dê um nome ao objeto da função. Você pode então usar esse nome como argumento ou valor de retorno. Aqui está o mesmo exemplo de filtro usando uma declaração def local: aList = \[1, 2, 3, 4, 5, 6, 7, 8, 9\] baixo = 3 alta = 7 def dentro dos _limites (valor, l = baixo, h = alto): return h> valor> l filter (dentro dos_ limites, aList) # retorna: \[4, 5, 6\] Embora o lambda possa ocasionalmente ser útil, muitos usuários do Python preferem def, que é mais geral, e pode tornar seu código mais legível se você escolher um nome razoável para a função. {mospagebreak title = Geradores} Quando o corpo de uma função contém uma ou mais ocorrências do rendimento da palavra-chave, a função é conhecida como um gerador. Quando você chama um gerador, o corpo da função não é executado. Em vez disso, chamar o gerador retorna um objeto iterador especial que envolve o corpo da função, suas variáveis ​​locais (incluindo seus parâmetros) e o ponto atual de execução, que é inicialmente o início da função. Quando o próximo método deste objeto iterador é chamado, o corpo da função é executado até a próxima instrução yield, que recebe o seguinte formato: expressão de rendimento Quando uma instrução yield é executada, a execução da função é "congelada", com o ponto atual de execução e variáveis ​​locais intactas, e a expressão seguinte yield é retornada como o resultado do próximo método. Quando o próximo é chamado novamente, a execução do corpo da função é retomada de onde parou, até a próxima declaração de rendimento. Se o corpo da função terminar ou executar uma instrução de retorno, o iterador gerará uma exceção StopIteration para indicar que a iteração foi concluída. instruções de retorno em um gerador não podem conter expressões. Um gerador é uma maneira muito útil de construir um iterador. Como a maneira mais comum de usar um iterador é fazer um loop com uma instrução for, você normalmente chama um gerador assim: para avariable em somegenerator (argumentos): Por exemplo, digamos que você deseje uma sequência de números contando de 1 a N e depois novamente para 1. Um gerador pode ajudar: def updown (N): para x em xrange (1, N): yield x para x em xrange (N, 0, -1): yield x para i em updown (3): imprimir i # impressões: 1 2 3 2 1 Aqui está um gerador que funciona um pouco como a função xrange integrada, mas retorna uma seqüência de valores de ponto flutuante em vez de uma sequência de inteiros: def frange (iniciar, parar, passo = 1.0): enquanto iniciar