Ostatnio zacząłem grać z Pythonem i natrafiłem na coś dziwnego w sposobie działania zamknięć. Rozważ następujący kod:
adders=[0,1,2,3]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
Buduje prostą tablicę funkcji, które pobierają pojedyncze dane wejściowe i zwracają dane dodane przez liczbę. Funkcje są zbudowane w forpętli, w której iterator ibiegnie od 0do 3. Dla każdej z tych liczb lambdatworzona jest funkcja, która przechwytuje ii dodaje ją do danych wejściowych funkcji. Ostatnia linia wywołuje drugą lambdafunkcję z 3parametrem. Ku mojemu zaskoczeniu wynik był 6.
Spodziewałem się 4. Moje rozumowanie brzmiało: w Pythonie wszystko jest przedmiotem, a zatem każda zmienna jest niezbędnym wskaźnikiem do niej. Podczas tworzenia lambdazamknięć i, spodziewałem się, że zapisze wskaźnik do obiektu liczb całkowitych, na który wskazuje aktualnie i. Oznacza to, że iprzypisany nowy obiekt liczby całkowitej nie powinien wpływać na wcześniej utworzone zamknięcia. Niestety, sprawdzenie adderstablicy w debuggerze pokazuje, że tak. Wszystkie lambdafunkcje znajdują się w ostatniej wartości i, 3, co powoduje adders[1](3)powrót 6.
Zastanawiam się co do następujących rzeczy:
- Co dokładnie rejestrują zamknięcia?
- Jaki jest najbardziej elegancki sposób przekonania
lambdafunkcji do przechwytywania bieżącej wartościiw sposób, który nie ulegnie zmianie poizmianie jej wartości?
iopuszcza przestrzeń nazw?
print iże nie będzie działać po pętli. Ale przetestowałem to dla siebie i teraz rozumiem, co masz na myśli - to działa. Nie miałem pojęcia, że zmienne pętli pozostały po pytle w ciele pętli.
if, with, tryitd.