Ce n' (lambda) les fermetures de fonction de capture?

Récemment, j'ai commencé à jouer avec Python et je suis autour de quelque chose de particulier dans la façon dont les fermetures de travail. Considérons le code suivant:

adders=[0,1,2,3]

for i in [0,1,2,3]:
   adders[i]=lambda a: i+a

print adders[1](3)

Il construit un tableau simple de fonctions que de prendre une seule entrée et de retour que l'entrée ajoutée par un nombre. Les fonctions sont construits dans for boucle où l'itérateur i s'exécute à partir de 0 à 3. Pour chacun de ces numéros, un lambda fonction est créée, qui capte i et l'ajoute à l'entrée de la fonction. La dernière ligne appelle la deuxième lambda fonction avec 3 en tant que paramètre. À ma grande surprise, la sortie a été 6.

Je m'attendais à un 4. Mon raisonnement était: en Python, tout est objet et ainsi, chaque variable est essentiel qu'un pointeur vers elle. Lors de la création de la lambda fermetures pour i, je m'attendais à stocker un pointeur vers l'objet integer actuellement pointée par i. Cela signifie que lorsque i assigné un nouvel objet integer il ne faut pas en effet le bouclage. Malheureusement, l'inspection de l' adders tableau à l'intérieur d'un débogueur montre qu'il n'. Tous les lambda, référez-vous à la dernière valeur de i, 3, qui résultats dans adders[1](3) retour 6.

Qui me font me demander sur les éléments suivants:

  • Que font les fermetures de saisir exactement?
  • Quelle est la façon la plus élégante de convaincre le lambda fonctions de capture de la valeur actuelle de i d'une manière qui ne sera pas affectée lorsque i modifie sa valeur?
J'ai eu ce problème dans le code de l'INTERFACE utilisateur. M'ont rendu fou. L'astuce est de se rappeler que les boucles ne pas créer un nouveau champ d'application.
Comment i quitter l'espace de noms?
Eh bien, j'allais dire que print i ne fonctionne pas après la boucle. Mais je l'ai testé pour moi et maintenant je vois ce que tu veux dire - il ne fonctionne pas. Je n'avais aucune idée que les variables de boucle persisté après le corps de la boucle en python.
Ouais, c'est ce que je voulais dire. De même pour if, with, try etc.
C'est dans l'officiel de Python FAQ, en vertu de la Pourquoi ne lambdas défini en boucle, avec des valeurs différentes, tous retournent le même résultat?, avec à la fois une explication et la solution de contournement.

OriginalL'auteur Boaz | 2010-02-19