Closures em Python Explicados: Como Funções Aninhadas Capturam Variáveis
Closures em Python
Descubra como closures Python funcionam, como defini-las e por que são essenciais para código limpo e eficiente.
Variáveis Nonlocal em Função Aninhada
Antes de explorar closures, é crucial entender funções aninhadas e variáveis nonlocal. Função definida dentro de outra função é chamada função aninhada. Tais funções podem ler variáveis de seu escopo envolvente.
Em Python, essas variáveis non-local são read-only por padrão. Para modificá-las, você deve declarar explicitamente variável como nonlocal dentro da função aninhada.
Abaixo exemplo simples mostrando função aninhada acessando variável non-local.
def print_msg(msg):
# Função externa
def printer():
# Função aninhada
print(msg)
printer() # Executar
print_msg("Hello")
Saída
Hello
A função aninhada printer() pode acessar variável msg de seu escopo externo.
Definindo Função Closure
E se função externa retornasse função aninhada em vez de chamá-la? Código ficaria assim:
def print_msg(msg):
def printer():
print(msg)
return printer # Retornar função aninhada
# Armazenar função retornada
another = print_msg("Hello")
another()
Saída
Hello
Note que função printer ainda lembra valor de msg mesmo após print_msg terminar execução. Esse fenômeno — onde função retém acesso a variáveis de seu escopo definidor — é chamado closure em Python.
Para ilustrar mais, delete função original e veja que função retornada ainda funciona:
>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
... NameError: name 'print_msg' is not defined
Função retornada continua funcionando porque capturou dados necessários em seu closure.
Quando Temos Closures?
Em Python, closure existe quando função aninhada:
- é definida dentro de outra função.
- referencia variável de sua função envolvente.
- é retornada pela função externa.
Quando Usar Closures?
Closures oferecem várias vantagens:
- Eliminam necessidade de variáveis globais, melhorando encapsulamento.
- Fornecem alternativa leve a classes de método único, mantendo código conciso.
- Permitem padrões funcionais como decorators, onde wrapper function precisa acessar argumentos da função original.
Abaixo exemplo comum: factory que cria funções multiplicadoras.
def make_multiplier_of(n):
def multiplier(x):
return x * n
return multiplier
# Criar multiplicadores específicos
times3 = make_multiplier_of(3)
times5 = make_multiplier_of(5)
print(times3(9)) # 27
print(times5(3)) # 15
print(times5(times3(2))) # 30
Saída
27 15 30
Sintaxe de decorators do Python depende fortemente de closures. Quando você escreve decorator, função wrapper captura função que decora, formando closure.
Para inspecionar closure, use atributo __closure__. Retorna tupla de objetos cell que guardam valores enclausurados. Exemplo:
>>> make_multiplier_of.__closure__
>>> times3.__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)
Atributo cell_contents de cada cell guarda valor real capturado pelo closure:
>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5
Entender closures capacita você a escrever código Python mais limpo e modular que evita globals desnecessários e abraça paradigmas funcionais.
python
- Dominando Tipos de Dados em Python: Guia Prático
- Dominando Operadores em Python: Guia Completo
- Dominando a Declaração Pass em Python: Guia Prático
- Funções Lambda em Python: Guia Prático para Funções Anônimas
- Dominando Dicionários em Python: Criação, Manipulação e Técnicas Avançadas
- Generators em Python: Iteração Eficiente e Casos de Uso Avançados
- Dominando Decorators em Python: Aprimore Funções com Técnicas de Especialista
- Dominando o Método strip() do Python: Guia Completo e Exemplos Práticos
- Dominando Funções Lambda em Python: Exemplos Práticos e Boas Práticas
- Função abs() em Python: Calcular Valores Absolutos para Números e Complexos