2016-04-23 19 views
16

ho provato il seguente codice in Python 3.5.1:comprensione dizionario con funzioni lambda dà risultati errati

>>> f = {x: (lambda y: x) for x in range(10)} 
>>> f[5](3) 
9 

E 'ovvio che questo dovrebbe tornare 5. Non capisco da dove provenga l'altro valore e non sono riuscito a trovare nulla.

Sembra che si tratti di un riferimento al riferimento - restituisce sempre la risposta di f[9], che è l'ultima funzione assegnata.

Qual è l'errore qui, e come dovrebbe essere fatto in modo che funzioni correttamente?

risposta

14

Lo scope Python è lessicale. Una chiusura farà riferimento al nome e all'ambito della variabile, non all'oggetto/valore effettivo della variabile.

Succede che ogni lambda è catturare la variabile xnon il valore di x.

Alla fine del ciclo variabile x è destinata a 9, quindi ogni lambda farà riferimento a questo x il cui valore è 9.

Perché @ risposta di Chrisp funziona:

make_func forza il valore di x da valutare (dato che è passato in una funzione). Pertanto, il lambda viene prodotto con il valore di x attualmente ed evitiamo il problema dell'ambito sopra descritto.

def make_func(x): 
    return lambda y: x 

f = {x: make_func(x) for x in range(10)} 
+7

Una scorciatoia alternativa sarebbe 'f = {x: (lambda y, x = x: x) per x nella gamma (10)}', perché argomenti di default sono vincolati al momento definizione, così legherebbero il _valore_ di 'x', non il _name_' x'. – ShadowRanger

+0

Questa può sembrare una domanda molto stupida (non ho familiarità con lambda), ma come funziona make_func (x)? Posso immaginare che f [5] (3) significa -> f = {5: make_func (5)}. Allora, come è che make_func (5) (3) è uguale a 5? – Adib

+1

La comprensione del dizionario rende le chiavi del dizionario degli interi ai valori delle funzioni. f [5] restituisce il valore nel dizionario digitato per 5, che risulta essere la funzione lambda y: x. Nota che lambda ignora ciò che è passato in (y) e restituisce sempre x. Questo è il motivo per cui il lambda restituirà 5 o 9 (a causa del problema descritto sopra). – gnicholas

6

Il seguente dovrebbe funzionare:

def make_func(x): 
    return lambda y: x 

f = {x: make_func(x) for x in range(10)} 

Il x nel codice finisce riferimento all'ultimo x valore, che è 9, ma nel mio essa si riferisce alla x nell'ambito funzione.