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() # 8
Aqui, 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 inner
Quando 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() # 8
Usando 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)) # 35
Aqui, 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 * m
Essa 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)) # 30
O 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)) # 35
Conclusã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.