Récemment, j'ai commencé à jouer avec Python et j'ai trouvé quelque chose de particulier dans le fonctionnement des fermetures. Considérez 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 crée un tableau simple de fonctions qui prennent une seule entrée et retournent cette entrée ajoutée par un nombre. Les fonctions sont construites en forboucle où l'itérateur iva de 0à 3. Pour chacun de ces nombres, une lambdafonction est créée qui la capture iet l'ajoute à l'entrée de la fonction. La dernière ligne appelle la deuxième lambdafonction avec 3comme paramètre. À ma grande surprise, la sortie était 6.
Je m'attendais à un 4. Mon raisonnement était: en Python, tout est un objet et donc chaque variable est un pointeur essentiel pour lui. Lors de la création des lambdafermetures pour i, je m'attendais à ce qu'il stocke un pointeur sur l'objet entier actuellement pointé par i. Cela signifie que lorsqu'il est iaffecté à un nouvel objet entier, il ne doit pas affecter les fermetures précédemment créées. Malheureusement, l'inspection du adderstableau dans un débogueur montre que c'est le cas. Toutes les lambdafonctions se rapportent à la dernière valeur i, 3dont les résultats en adders[1](3)retour 6.
Ce qui me fait me demander ce qui suit:
- Que capturent exactement les fermetures?
- Quelle est la façon la plus élégante de convaincre les
lambdafonctions de capturer la valeur actuelle d'iune manière qui ne sera pas affectée lors d'unichangement de valeur?
iquitte l'espace de noms?
print icela ne fonctionnerait pas après la boucle. Mais je l'ai testé par moi-même et maintenant je vois ce que vous voulez dire - cela fonctionne. Je n'avais aucune idée que les variables de boucle persistaient après le corps de la boucle en python.
if, with, tryetc.