Recentemente, comecei a brincar com o Python e descobri algo peculiar na maneira como os fechamentos funcionam. Considere o seguinte código:
adders=[0,1,2,3]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
Ele cria uma matriz simples de funções que recebem uma única entrada e retornam essa entrada adicionada por um número. As funções são construídas em for
loop onde o iterador i
é executado de 0
para 3
. Para cada um desses números lambda
, é criada uma função que captura i
e a adiciona à entrada da função. A última linha chama a segunda lambda
função com 3
como parâmetro. Para minha surpresa, a saída foi 6
.
Eu esperava um 4
. Meu raciocínio era: no Python tudo é um objeto e, portanto, toda variável é um ponteiro essencial para ele. Ao criar os lambda
fechamentos para i
, eu esperava que ele armazenasse um ponteiro para o objeto inteiro atualmente apontado por i
. Isso significa que, quando i
atribuído um novo objeto inteiro, ele não deve afetar os fechamentos criados anteriormente. Infelizmente, inspecionar a adders
matriz em um depurador mostra que sim. Todas as lambda
funções referem-se ao último valor i
, 3
que resulta em adders[1](3)
retorno 6
.
O que me faz pensar sobre o seguinte:
- O que os fechamentos capturam exatamente?
- Qual é a maneira mais elegante de convencer as
lambda
funções a capturar o valor atual dei
uma maneira que não seja afetada quandoi
o valor for alterado?
i
sai do espaço para nome?
print i
não funcionaria após o loop. Mas eu testei por mim mesmo e agora entendo o que você quer dizer - funciona. Eu não tinha ideia de que variáveis de loop permaneciam após o corpo do loop em python.
if
, with
, try
etc.