Di recente ho iniziato a giocare con Python e ho scoperto qualcosa di strano nel modo in cui funzionano le chiusure. Considera il seguente codice:
adders=[0,1,2,3]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
Costruisce un semplice array di funzioni che accettano un singolo input e restituiscono quell'input aggiunto da un numero. Le funzioni sono costruiti in forciclo in cui l'iteratore iva da 0a 3. Per ciascuno di questi numeri lambdaviene creata una funzione che acquisisce ie la aggiunge all'input della funzione. L'ultima riga chiama la seconda lambdafunzione con3 come parametro. Con mia sorpresa l'output è stato 6.
Mi aspettavo a 4. Il mio ragionamento era: in Python ogni cosa è un oggetto e quindi ogni variabile è essenziale un puntatore ad esso. Durante la creazione delle lambdachiusure per i, mi aspettavo che memorizzasse un puntatore all'oggetto intero attualmente indicato da i. Ciò significa che quando iassegnato un nuovo oggetto intero non dovrebbe influenzare le chiusure precedentemente create. Purtroppo, l'ispezione addersdell'array all'interno di un debugger mostra che lo fa. Tutte le lambdafunzioni si riferiscono all'ultimo valore i, 3, che si traduce in adders[1](3)ritorno 6.
Il che mi fa chiedere quanto segue:
- Cosa catturano esattamente le chiusure?
- Qual è il modo più elegante per convincere le
lambdafunzioni a catturare il valore attualeiin un modo che non sarà influenzato quandoicambia il suo valore?
ilascia lo spazio dei nomi?
print inon avrebbe funzionato dopo il ciclo. Ma l'ho testato da solo e ora capisco cosa intendi: funziona. Non avevo idea che le variabili del loop indugiassero dopo il corpo del loop in Python.
if, with, tryecc