Liaison de Python lambda aux valeurs locales

Le code suivant crache 1deux fois, mais je m'attends à voir 0et ensuite 1.

def pv(v):
print v
x = []
for v in range(2):
x.append(lambda: pv(v))
for xx in x:
xx()

Je m'attendais à ce que python lambdas se lie à la référence vers laquelle pointe une variable locale, dans les coulisses. Cependant cela ne semble pas être le cas. J'ai rencontré ce problème dans un grand système où le lambda fait l'équivalent C++ moderne d'une liaison ('boost::bind' par exemple) où, dans ce cas, vous vous lieriez à un ptr intelligent ou copieriez construire une copie pour le lambda.

Alors, comment lier une variable locale à une fonction lambda et lui faire conserver la référence correcte lorsqu'elle est utilisée? Je suis assez abasourdi par le comportement car je ne m'attendrais pas à cela d'un langage avec un ramasse-miettes.


Solution du problème

Passez x.append(lambda: pv(v))à x.append(lambda v=v: pv(v)).

Vous vous attendez à ce que "python lambdas se lie à la référence vers laquelle une variable locale pointe, derrière la scène", mais ce n'est pas ainsi que Python fonctionne. Python recherche le nom de la variable au moment où la fonction est appelée, et non lors de sa création. L'utilisation d'un argument par défaut fonctionne car les arguments par défaut sont évalués lorsque la fonction est créée, et non lorsqu'elle est appelée.

Ce n'est pas quelque chose de spécial à propos des lambdas. Considérer:

x = "before foo defined"
def foo():
print x
x = "after foo was defined"
foo()

impressions

after foo was defined

Commentaires

Posts les plus consultés de ce blog

Erreur Symfony : "Une exception a été levée lors du rendu d'un modèle"

Détecter les appuis sur les touches fléchées en JavaScript

Une chaîne vide donne "Des erreurs ont été détectées dans les arguments de la ligne de commande, veuillez vous assurer que tous les arguments sont correctement définis"