2013-02-06 30 views
5

Dlaczego ten kod wyświetla "d, d, d, d", a nie "a, b, c, d"? Jak mogę go zmodyfikować, aby wydrukować "a, b, c, d"?Zakres zmiennej wewnątrz lambda

cons = [] 
for i in ['a', 'b', 'c', 'd']: 
    cons.append(lambda: i) 
print ', '.join([fn() for fn in cons])  
+1

http://stackoverflow.com/questions/760688/use- value-of-variable-in-lambda-expression? rq = 1 – NPE

+2

Nie jestem pewien, czy rzeczywiście jest to dokładny duplikat - to nie jest pytanie, jak zmienić zachowanie, to pytanie, dlaczego zachowanie jest w ten sposób w pierwsze miejsce. –

+0

Zgadzam się z Kyle'em, bo warto, i spróbowałem odpowiedzieć w tym tonie. – jimwise

Odpowiedz

6

Co ciekawe, nie jest zmienną zakres problemu, lecz quesiton semantyki pytona w for pętli (i zmiennych Pythona).

Zgodnie z oczekiwaniami, i wewnątrz lambda poprawnie odnosi się do zmiennej i w najbliższym zasięgu. Jak na razie dobrze.

jednak spodziewasz to oznaczać poniższych sytuacji:

for each value in the list ['a', 'b', 'c', 'd']: 
    instantiate a new variable, i, pointing to the current list member 
    instantiate a new anonymous function, which returns i 
    append this function to cons 

Co właściwie się dzieje, jest to:

instantiate a new variable i 
for each value in the list ['a', 'b', 'c', 'd']: 
    make i refer to the current list member 
    instantiate a new anonymous function, which returns i 
    append this function to cons 

Zatem kod jest dołączenie samą zmienną i do lista cztery razy - i do czasu zakończenia pętli, i ma wartość 'd'.

Zauważ, że jeśli funkcje Pythona trwało i wrócił wartość ich argumentów/wartości zwracane przez wartości, byś nie zauważył tego, jak zawartość od i byłyby kopiowane przy każdym połączeniu append (lub, w przypadku to ważne, przy każdym powrocie z anonimowej funkcji utworzonej z lambda). W rzeczywistości jednak zmienne Pythona są zawsze odwołań do określonego obiektu - a tym samym wszystkie cztery kopie i wszystkie odnoszą się do 'd' do końca swojej pętli.

+0

Możesz to sprawdzić, drukując "i" po wyjściu z pętli. Możesz również sprawdzić, czy wszystkie cztery funkcje lambda są technicznie różnymi funkcjami, drukując 'cons' i porównując identyfikatory. –

+0

Dzięki. To jest bardzo pomocne. – mickeybob

2

Po utworzeniu zamknięcia zmienne, które są "zamknięte" przez lambda (w tym przypadku i) są powiązane nazwą, a nie wartością. Dlatego za każdym razem, gdy wywołasz swoje lambdy, użyją one ostatniej wartości "i".

2

Oto prosty fix trzeba wykonać tę pracę:

cons = [] 
for i in ['a', 'b', 'c', 'd']: 
    cons.append(lambda i=i: i) 
print ', '.join([fn() for fn in cons])  
0

odpowiedź 'ERIC' jako zrozumieniem:

cons =[lambda i= i:i for i in ['a', 'b', 'c', 'd']] 
print ', '.join([fn() for fn in cons])  
Powiązane problemy