2009-12-03 12 views

Respuesta

18

Técnicamente, la expresión lambda es cerrado sobre el i que es visible en el ámbito global, que es último conjunto a 9. Es la mismai siendo referido en todas las 10 lambdas. Por ejemplo,

i = 13 
print b[3]() 

En la función de makeFun, la lambda se cierra en el i que se define cuando se invoca la función. Esos son diez diferentesi s.

+0

Ok, ahora esto tiene sentido para mí. ¡Gracias! – Anssi

1

Lambdas en la cuota de pitón la variable de alcance son creados en en su primer caso, el alcance de la lambda es makeFun de. En su segundo caso, es el i global, que es 9 porque es un remanente del ciclo.

Eso es lo que entiendo de todos modos ...

1

Buena captura. La lambda en la lista de comprensión está viendo el mismo local i todo el tiempo.

Puede volver a escribir como:

a = [] 
for i in range(10): 
    a.append(makefun(i)) 

b = [] 
for i in range(10): 
    b.append(lambda: i) 

con el mismo resultado.

+0

No estoy seguro de lo que estás tratando de decir. En su ejemplo, 'b [2]()' también devuelve 9. –

+0

Estoy diciendo que es equivalente a la lista de comprensiones; no es que a y b y lo mismo. Me imaginé que los bucles 'for' deletreados harían más fácil ver de dónde viene' i'. –

7

Un conjunto de funciones (a) opera en el argumento pasado y el otro (b) opera en una variable global que se establece a continuación a 9. Comprobar el desmontaje:

>>> import dis 
>>> dis.dis(a[2]) 
    1   0 LOAD_DEREF    0 (i) 
       3 RETURN_VALUE 
>>> dis.dis(b[2]) 
    1   0 LOAD_GLOBAL    0 (i) 
       3 RETURN_VALUE 
>>> 
18

Como otros han dicho, el alcance es el problema. Tenga en cuenta que puede resolver esto añadiendo un argumento adicional a la expresión lambda y asignándole un valor por defecto:

>> def makeFun(i): return lambda: i 
... 
>>> a = [makeFun(i) for i in range(10)] 
>>> b = [lambda: i for i in range(10)] 
>>> c = [lambda i=i: i for i in range(10)] # <-- Observe the use of i=i 
>>> a[2](), b[2](), c[2]() 
(2, 9, 2) 

El resultado es que i se coloca ahora de forma explícita en un ámbito limitado a la expresión lambda.

3

Para añadir un poco de claridad (al menos en mi mente)

def makeFun(i): return lambda: i 
a = [makeFun(i) for i in range(10)] 
b = [lambda: i for i in range(10)] 

un makeFun utiliza (i) que es una función con un argumento.

b utiliza lambda: i que es una función sin argumentos.El i que utiliza es muy diferente de la anterior

Para hacer ayb igual podemos hacer ambas funciones a utilizar sin argumentos:

def makeFun(): return lambda: i 
a = [makeFun() for i in range(10)] 
b = [lambda: i for i in range(10)] 

Ahora ambas funciones utilizan el mundial i

>>> a[2]() 
9 
>>> b[2]() 
9 
>>> i=13 
>>> a[2]() 
13 
>>> b[2]() 
13 

O (más útil) que ambos utilizan un argumento:

def makeFun(x): return lambda: x 
a = [makeFun(i) for i in range(10)] 
b = [lambda x=i: x for i in range(10)] 

deliberadamente he cambiado con x donde la variable es local. Ahora :

>>> a[2]() 
2 
>>> b[2]() 
2 

éxito!