2009-12-03 2 views

Répondre

18

Techniquement, l'expression lambda est fermée sur la i qui est visible dans la portée globale, qui est le dernier jeu à 9. Il est le mêmei étant mentionné dans tous les 10 lambdas. Par exemple,

i = 13 
print b[3]() 

Dans la fonction makeFun, le lambda ferme sur la i qui est défini lorsque la fonction est invoquée. Ceux-ci sont dix différentsi s.

+0

Ok, maintenant c'est logique pour moi. Merci! – Anssi

1

lambdas en part python la SCOPE variables qu'ils sont créés dans Dans votre premier cas, la portée du lambda est makeFun de. Dans votre deuxième cas, c'est le i global, qui est 9 parce que c'est un reste de la boucle.

C'est ce que je comprends de toute façon ...

1

Belle prise. Le lambda dans la compréhension de la liste voit le même i chaque fois.

Vous pouvez réécrire comme:

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

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

avec le même résultat.

+0

Je ne suis pas sûr de ce que vous essayez de dire. Dans votre exemple, 'b [2]()' renvoie également 9. –

+0

Je dis que c'est équivalent à la liste des compréhensions; pas que a et b et la même chose. Je pensais que les boucles 'for' épelées rendraient plus facile de voir d'où vient le' i'. –

7

Un ensemble de fonctions (a) fonctionne sur l'argument passé et l'autre (b) fonctionne sur une variable globale qui est ensuite réglée sur 9. Vérifiez le démontage: Comme d'autres ont déclaré

>>> 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

, la portée est le problème. Notez que vous pouvez résoudre ce problème en ajoutant un argument supplémentaire à l'expression lambda et en lui attribuant une valeur par défaut:

>> 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) 

Le résultat est que i est maintenant explicitement placé dans un champ limité à l'expression lambda.

3

Pour ajouter un peu de clarté (au moins dans mon esprit)

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

utilise un makeFun (i) qui est une fonction avec un argument. B utilise lambda: i qui est une fonction sans arguments.Le i utilise est très différente de la précédente

Pour a et b égale, nous pouvons faire les deux fonctions à utiliser aucun argument:

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

Maintenant, les deux fonctions utilisent le global i

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

Ou (plus utile) faire à la fois utiliser un argument:

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

J'ai délibérément changé i avec x où la variable est locale. maintenant:

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

Succès!