Closures em Python
Um closure representa uma função que lembra seu ambiente léxico, mesmo quando é executada fora de seu escopo original.
Tecnicamente, um closure inclui três componentes principais:
- Uma função externa, que define um escopo e na qual algumas variáveis e parâmetros são definidos — este é o ambiente léxico
- As variáveis e parâmetros que são definidos na função externa.
- Uma função interna, que utiliza as variáveis e parâmetros da função externa.
Em Python, os closures são definidos com o uso de funções locais:
def outer(): # função externa
n = 5 # ambiente léxico — variável local
def inner(): # função interna
nonlocal n
n += 1 # operações com o ambiente léxico
print(n)
return inner
fn = outer() # fn = inner, já que a função outer retorna a função inner
# chamando a função interna inner
fn() # 6
fn() # 7
fn() # 8Aqui, a função outer define a variável local n, que é o ambiente léxico para a função interna inner.
Dentro da função outer, a função interna inner acessa o ambiente léxico — a variável n —, incrementa seu valor em um, e imprime o resultado no console:
def inner(): # função interna
nonlocal n
n += 1 # operações com o ambiente léxico
print(n)A função inner é então retornada pela função outer:
return innerQuando chamamos a função outer, a variável fn recebe a função interna inner:
fn = outer()A variável fn é um closure, ou seja, combina a função com o ambiente no qual foi criada. Mesmo que estejamos chamando a função interna fora da função externa, ela ainda lembra seu ambiente léxico e pode acessá-lo e modificá-lo, como podemos ver no resultado impresso:
fn() # 6
fn() # 7
fn() # 8Usando Parâmetros
Além das variáveis externas, os parâmetros da função também fazem parte do ambiente léxico. Vamos ver um exemplo com o uso de parâmetros:
def multiply(n):
def inner(m): return n * m
return inner
fn = multiply(5)
print(fn(6)) # 30
print(fn(7)) # 35Aqui, a função externa multiply retorna uma função que recebe um número e retorna o resultado da multiplicação.
Quando chamamos a função multiply, obtemos a função interna inner:
def inner(m): return n * mEssa função lembra o ambiente no qual foi criada, especificamente o valor do parâmetro n. Ela também recebe o parâmetro m e retorna o produto entre n e m.
No final, ao chamar a função multiply, a variável fn recebe a função interna inner e seu ambiente léxico: o valor do parâmetro n:
fn = multiply(5)Nesse caso, o parâmetro n é igual a 5.
Quando chamamos a função interna com o número 6:
print(fn(6)) # 30O número 6 é passado como parâmetro m, e a função retorna o produto de n e m, ou seja, 5 * 6 = 30.
Esse código pode ser simplificado com o uso de expressões lambda:
def multiply(n): return lambda m: n * m
fn = multiply(5)
print(fn(6)) # 30
print(fn(7)) # 35Conclusão
Os closures são uma forma eficiente de criar funções dinâmicas que "lembram" o contexto em que foram definidas, permitindo que essas funções mantenham o acesso a variáveis e parâmetros mesmo após o término da execução da função externa.