Encapsular variáveis dentro de encerramentos para removê-las das assinaturas de função é uma técnica frequentemente usada para estruturação de código eficiente. No entanto, no caso de lambdas não aninhados, o fechamento retém o valor final da variável, levando a problemas ao tentar acessar valores específicos com base na variável iterativa.
Considere o snippet de código fornecido:
names = ['a', 'b', 'c'] def test_fun(name, x): print(name, x) def gen_clousure(name): return lambda x: test_fun(name, x) funcs1 = [gen_clousure(n) for n in names] funcs2 = [lambda x: test_fun(n, x) for n in names] # Expected output for funcs1 for f in funcs1: f(1) # Unexpected output for funcs2 (returns last element for all cases) for f in funcs2: f(1)
Compreender a razão por trás dessa discrepância é crucial para a utilização eficaz do fechamento.
O conceito fundamental nesta situação é escopo variável nos fechamentos . Os fechamentos contêm inerentemente os nomes das variáveis em vez de seus valores. Isso significa que a avaliação da variável ocorre quando a execução do lambda é iniciada, e não no momento da definição do lambda.
No caso de funcs2, quando você executa lambda x: test_fun(n, x), a variável n não é avaliado durante a definição de lambda. Em vez disso, a avaliação só acontece na chamada lambda. Nesse ponto, n contém o último valor do loop (que é 'c' neste caso). Consequentemente, a função f sempre utiliza 'c' como o valor de n, independentemente da entrada x.
Para resolver esse problema e obter a funcionalidade desejada, a variável n deve ser capturada no escopo da função lambda. Isso pode ser conseguido passando a variável como um argumento para o lambda, conforme mostrado a seguir:
funcs2 = [lambda x: test_fun(n, x) for n in names if 2 > 0]
Ao incluir esta instrução if adicional que sempre é verdadeira, forçamos o lambda a tomar o valor de n como argumento, garantindo o comportamento personalizado esperado em todos os casos.
Como alternativa, você pode agrupar o lambda não aninhado em uma função aninhada, evitando efetivamente o acesso a variáveis não declaradas no escopo. O código a seguir ilustra essa abordagem:
def makeFunc(n): return lambda x: x n stuff = [makeFunc(n) for n in [1, 2, 3]] for f in stuff: print(f(1))
Aqui, a variável n é capturada na função makeFunc, garantindo o escopo adequado dentro do lambda.
Compreendendo e gerenciando o escopo da variável em encerramentos é essencial para design e depuração de código eficazes. As principais conclusões são:
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3