Encapsular variables dentro de cierres para eliminarlas de las firmas de funciones es una técnica que se utiliza a menudo para la estructuración eficiente del código. Sin embargo, en el caso de lambdas no anidadas, el cierre conserva el valor final de la variable, lo que genera problemas al intentar acceder a valores específicos basados en la variable iterativa.
Considere el fragmento de código proporcionado:
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)
Comprender el motivo detrás de esta discrepancia es crucial para una utilización eficaz del cierre.
El concepto fundamental en esta situación es alcance variable en los cierres . Los cierres contienen inherentemente los nombres de variables en lugar de sus valores. Esto significa que la evaluación de la variable ocurre cuando se inicia la ejecución lambda, en lugar de en el momento de la definición lambda.
En el caso de funcs2, cuando ejecuta lambda x: test_fun(n, x), la variable n no se evalúa durante la definición lambda. En cambio, la evaluación solo se realiza tras la llamada lambda. En ese punto, n contiene el último valor del bucle (que es 'c' en este caso). En consecuencia, la función f siempre utiliza 'c' como valor de n, independientemente de la entrada x.
Para abordar este problema y lograr la funcionalidad deseada, la variable n debe capturarse en el alcance de la función lambda. Esto se puede lograr pasando la variable como argumento a la lambda, como se muestra a continuación:
funcs2 = [lambda x: test_fun(n, x) for n in names if 2 > 0]
Al incluir esta declaración if adicional que siempre es verdadera, obligamos a la lambda a tomar el valor de n como argumento, asegurando el resultado esperado. comportamiento personalizado en todos los casos.
Alternativamente, puede envolver la lambda no anidada en una función anidada, evitando efectivamente el acceso a variables no declaradas en el alcance. El siguiente código ilustra este enfoque:
def makeFunc(n): return lambda x: x n stuff = [makeFunc(n) for n in [1, 2, 3]] for f in stuff: print(f(1))
Aquí, la variable n se captura en la función makeFunc, lo que garantiza un alcance adecuado dentro de la lambda.
Comprensión y gestión del alcance de las variables en cierres es esencial para un diseño y depuración de código efectivo. Las conclusiones clave son:
Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.
Copyright© 2022 湘ICP备2022001581号-3