¿Por qué estas dos ‘x’ se refieren a diferentes variables?

En este código, la x en la lambda se refiere a la x en la statement for. Entonces y[0]() devuelve 2:

 x = 0 y = [lambda : x for x in range(3)] y[0]() 

Pero en este código, la x en la lambda se refiere a x global, por lo que x[0]() devuelve x global:

 x = [lambda : x for x in range(3)] x[0]() 

Quiero saber por qué la x en la lambda se refiere a la x local en la primera parte del código, pero global x en la segunda pieza del código.

x refiere al x global en ambas piezas de código. De hecho, no hay nada más que una x global en ambas piezas de código. Aquí no hay variables locales, solo variables globales.

En el primer ejemplo, el valor global de x es 2, porque ese fue el último valor que le asignó la lista de comprensión. Las comprensiones de la lista filtran sus variables en el ámbito de la envolvente como lo describe @wim. Dado que el scope adjunto aquí es el scope global, la variable x se filtra hacia el scope global, sobrescribiendo el valor 0 que estableció anteriormente.

En el segundo ejemplo, crea la lista de comprensión, pero luego asigna su valor a la variable (global) x. Esto sobrescribe lo que ya estaba en x, por lo que el valor de la variable global x ahora es la lista.

En ambos casos, cuando llama a una de las funciones en la lista (¡cualquiera!), Devuelve el valor actual de x . Puedes ver esto aquí:

 >>> y = [lambda : x for x in range(3)] >>> y[0]() 2 >>> x = 88 >>> y[0]() 88 >>> x = [lambda : x for x in range(3)] >>> y = x >>> y[0]() [ at 0x017789B0>,  at 0x01828DB0>,  at 0x01828F30>] >>> x = 88 >>> y[0]() 88 

Supongo que estás en Python 2.x, donde en una lista de comprensión, la variable temporal “se filtra” en el espacio de nombres. Puedes leer acerca de por qué en esta publicación de blog de Guido .

En Python 2, la comprensión de la lista “filtra” la variable de control del bucle hacia el ámbito circundante … Esto fue un artefacto de la implementación original de las comprensiones de la lista; Fue uno de los “pequeños secretos sucios” de Python durante años.

Esto se ha solucionado en python 3.

No estoy seguro de por qué estás confundiendo las cosas con la lambda , aquí verás el mismo comportamiento en este caso más simple:

 >>> x = 'a' >>> y = [x for x in 'b','c'] >>> x 'c' >>> x = [x for x in 'b','c'] >>> x ['b', 'c'] 
 >>> x='a' >>>x = [lambda : x for x in range(3)] 

tan pronto como comienza la iteración, la x se asigna a 0 , se devuelve desde el range() (y se elimina la referencia a ‘a’). En la iteración final, el valor de x convierte en 2, y tan pronto como la LC sale, la LC se asigna a x , por lo que ahora x apunta a la LC.

ejemplo:

 >>> [x for x in range(3)] [0, 1, 2] >>> x 2 >>> x=[x for x in range(3)] >>> x [0, 1, 2]