Python lambda est contraignant pour les valeurs locales
Le code suivant crache 1
deux fois, je m'attends à voir 0
et puis 1
def pv(v) :
print v
def test() :
value = []
value.append(0)
value.append(1)
x=[]
for v in value :
x.append(lambda : pv(v))
return x
x = test()
for xx in x:
xx()
Je m'attendais python lambdas à se lier à la référence à une variable locale est pointant vers, derrière la scène. Cependant cela ne semble pas être le cas. J'ai enountered ce problème dans un système où le lambda est de faire C++moderne's equavalent d'un bind ('boost::bind par exemple), où dans de tels cas, vous devez le lier à un smart ptr ou copie contstruct une copie pour le lambda.
Alors, comment puis-je lier une variable locale à une fonction lambda et ont de conserver la référence correcte lorsque utilisé? Je suis assez sur le cul avec le comportement car je ne voudrais pas que cela à partir d'une langue avec un garbage collector.
Le code en question se présente comme suit (l3_e est la variable qui est à l'origine du problème) :
for category in cat :
for l2 in cat[category].entries :
for l3 in cat[category].entries[l2].entry["sub_entries"] :
l3_e = cat[category].entries[l2].entry["sub_entries"][l3]
url = "http://forums.heroesofnewerth.com/" + l3_e.entry["url"]
self.l4_processing_status[l3_e] = 0
l3_discovery_requests.append( Request(
url, callback = lambda response : self.parse_l4(response,l3_e)))
print l3_e.entry["url"]
return l3_discovery_requests
ah, ici, vous allez, près de dupliquer: lexicale-fermetures-en-python
Aussi, le premier morceau de code pour illustrer votre point parfaitement, pourquoi coller dans ce second morceau?
oui , je n'arrivais pas à l'exprimer correctement, j'ai essayé de reproduire la façon lua œuvres.
La partie étrange de Python, c'est que les variables de boucle persistent après la boucle, de sorte que les fonctions définies à l'intérieur de la boucle et le référencement de la variable de boucle, ne pas jeter un
NameError
si elle est appelée hors de la boucle. Dans la plupart des autres langues, les variables de boucle ne sont accessibles qu'à l'intérieur de la boucle elle-même.OriginalL'auteur Hassan Syed | 2012-05-04
Vous devez vous connecter pour publier un commentaire.
Changement
x.append(lambda : pv(v))
àx.append(lambda v=v: pv(v))
.Vous attendez "python lambdas à se lier à la référence à une variable locale est pointant vers, derrière la scène", mais ce n'est pas la façon Python fonctionne. Python cherche le nom de la variable au moment où la fonction est appelée, non pas quand il est créé. À l'aide d'un argument par défaut fonctionne parce que les arguments par défaut sont évaluées lors de la création de la fonction, et non pas lorsqu'elle est appelée.
Ce n'est pas quelque chose de spécial à propos de lambdas. Considérer:
imprime
Un plus évident alternative est d'utiliser
functools.partial
ou en servant d'une fonction d'assistance à créer les fermetures (def make_closure(v): return lambda: pv(v)
, vous pouvez le mettre danstest
).donc mon vrai code voudrais
lambda par1, par2 = l3_e : self.parse_l4(par1, par2)
?Si
v
était lui-même une référence (par opposition à unint
), puis je le prendre, il y aura pas être "en profondeur" de la copie?OriginalL'auteur Steven Rumbalski
Le lambda de la fermeture détient une référence à la variable utilisée, pas sa valeur, de sorte que si la valeur de la variable de modifications ultérieures, la valeur de la fermeture aussi des changements. Qui est, la fermeture de la valeur de la variable est résolu lorsque la fonction est appelée, non pas quand il est créé. (Python comportement n'est pas inhabituel dans le monde de la programmation fonctionnelle, pour ce que ça vaut.)
Il y a deux solutions:
Utiliser un argument par défaut, la liaison de la valeur actuelle de la variable par un nom local au moment de la définition.
lambda v=v: pv(v)
Utiliser un double-lambda et appeler immédiatement la première.
(lambda v: lambda: pv(v))(v)
OriginalL'auteur kindall