Recientemente comencé a jugar con Python y encontré algo peculiar en la forma en que funcionan los cierres. Considere el siguiente código:
adders=[0,1,2,3]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
Construye una matriz simple de funciones que toman una sola entrada y devuelven esa entrada agregada por un número. Las funciones se construyen en forbucle donde el iterador ise extiende desde 0a 3. Para cada uno de estos números lambda, se crea una función que captura iy agrega a la entrada de la función. La última línea llama a la segunda lambdafunción con 3como parámetro. Para mi sorpresa, la salida fue 6.
Esperaba un 4. Mi razonamiento fue: en Python todo es un objeto y, por lo tanto, cada variable es un puntero esencial. Al crear los lambdacierres para i, esperaba que almacenara un puntero al objeto entero al que apunta actualmente i. Eso significa que cuando se le iasigna un nuevo objeto entero no debería afectar los cierres creados anteriormente. Lamentablemente, la inspección de la addersmatriz dentro de un depurador muestra que sí. Todas las lambdafunciones se refieren al último valor de i, 3, que se traduce en adders[1](3)regresar 6.
Lo que me hace preguntarme sobre lo siguiente:
- ¿Qué capturan exactamente los cierres?
- ¿Cuál es la forma más elegante de convencer a las
lambdafunciones de capturar el valor actual deiuna manera que no se verá afectada cuandoicambie su valor?
ideja el espacio de nombres?
print ino funcionaría después del ciclo. Pero lo probé por mí mismo y ahora veo lo que quieres decir: funciona. No tenía idea de que las variables de bucle persistían después del cuerpo del bucle en Python.
if, with, tryetc.