Fechamentos Python
Fechamentos Python
Neste tutorial, você aprenderá sobre o encerramento do Python, como definir um encerramento e os motivos pelos quais você deve usá-lo.
Variável não local em uma função aninhada
Antes de entrar no que é um encerramento, temos que primeiro entender o que é uma função aninhada e uma variável não local.
Uma função definida dentro de outra função é chamada de função aninhada. Funções aninhadas podem acessar variáveis do escopo delimitador.
Em Python, essas variáveis não locais são somente leitura por padrão e devemos declará-las explicitamente como não locais (usando a palavra-chave não local) para modificá-las.
A seguir está um exemplo de uma função aninhada acessando uma variável não local.
def print_msg(msg):
# This is the outer enclosing function
def printer():
# This is the nested function
print(msg)
printer()
# We execute the function
# Output: Hello
print_msg("Hello")
Saída
Hello
Podemos ver que o
printer()
aninhado função foi capaz de acessar a msg não local variável da função envolvente. Definindo uma função de fechamento
No exemplo acima, o que aconteceria se a última linha da função
print_msg()
retornou o printer()
função em vez de chamá-lo? Isso significa que a função foi definida da seguinte forma:
def print_msg(msg):
# This is the outer enclosing function
def printer():
# This is the nested function
print(msg)
return printer # returns the nested function
# Now let's try calling this function.
# Output: Hello
another = print_msg("Hello")
another()
Saída
Hello
Isso é incomum.
O
print_msg()
função foi chamada com a string "Hello"
e a função retornada estava vinculada ao nome outro . Ao ligar para another()
, a mensagem ainda foi lembrada, embora já tivéssemos terminado de executar o print_msg()
função. Esta técnica pela qual alguns dados (
"Hello
neste caso) é anexado ao código é chamado de fechamento em Python . Esse valor no escopo delimitador é lembrado mesmo quando a variável sai do escopo ou a própria função é removida do namespace atual.
Tente executar o seguinte no shell do Python para ver a saída.
>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
...
NameError: name 'print_msg' is not defined
Aqui, a função retornada ainda funciona mesmo quando a função original foi excluída.
Quando teremos fechamentos?
Como visto no exemplo acima, temos um encerramento em Python quando uma função aninhada faz referência a um valor em seu escopo delimitador.
Os critérios que devem ser atendidos para criar o encerramento em Python estão resumidos nos pontos a seguir.
- Devemos ter uma função aninhada (função dentro de uma função).
- A função aninhada deve se referir a um valor definido na função delimitadora.
- A função delimitadora deve retornar a função aninhada.
Quando usar encerramentos?
Então, para que servem os fechamentos?
Os fechamentos podem evitar o uso de valores globais e fornecem alguma forma de ocultação de dados. Ele também pode fornecer uma solução orientada a objetos para o problema.
Quando existem poucos métodos (um método na maioria dos casos) a serem implementados em uma classe, os closures podem fornecer uma solução alternativa e mais elegante. Mas quando o número de atributos e métodos aumenta, é melhor implementar uma classe.
Aqui está um exemplo simples onde um encerramento pode ser mais preferível do que definir uma classe e criar objetos. Mas a preferência é toda sua.
def make_multiplier_of(n):
def multiplier(x):
return x * n
return multiplier
# Multiplier of 3
times3 = make_multiplier_of(3)
# Multiplier of 5
times5 = make_multiplier_of(5)
# Output: 27
print(times3(9))
# Output: 15
print(times5(3))
# Output: 30
print(times5(times3(2)))
Saída
27 15 30
Os Decoradores Python também fazem uso extensivo de closures.
Em uma nota final, é bom ressaltar que os valores incluídos na função de fechamento podem ser encontrados.
Todos os objetos de função têm um
__closure__
atributo que retorna uma tupla de objetos de célula se for uma função de fechamento. Referindo-se ao exemplo acima, sabemos times3
e times5
são funções de fechamento.
>>> make_multiplier_of.__closure__
>>> times3.__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)
O objeto célula possui o atributo cell_contents que armazena o valor fechado.
>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5
python