Domanda

Il seguente test ha esito negativo:

#!/usr/bin/env python
def f(*args):
    """
    >>> t = 1, -1
    >>> f(*map(lambda i: lambda: i, t))
    [1, -1]
    >>> f(*(lambda: i for i in t)) # -> [-1, -1]
    [1, -1]
    >>> f(*[lambda: i for i in t]) # -> [-1, -1]
    [1, -1]
    """
    alist = [a() for a in args]
    print(alist)

if __name__ == '__main__':
    import doctest; doctest.testmod()

In altre parole:

>>> t = 1, -1
>>> args = []
>>> for i in t:
...   args.append(lambda: i)
...
>>> map(lambda a: a(), args)
[-1, -1]
>>> args = []
>>> for i in t:
...   args.append((lambda i: lambda: i)(i))
...
>>> map(lambda a: a(), args)
[1, -1]
>>> args = []
>>> for i in t:
...   args.append(lambda i=i: i)
...
>>> map(lambda a: a(), args)
[1, -1]
È stato utile?

Soluzione

Sono diversi, perché il valore di i sia nell'espressione del generatore che nella lista è valutato pigramente, cioè quando le funzioni anonime sono invocate in f . < br> A quel punto, i è associato all'ultimo valore se t , che è -1.

Quindi, in sostanza, questo è ciò che fa la comprensione dell'elenco (anche per il genexp):

x = []
i = 1 # 1. from t
x.append(lambda: i)
i = -1 # 2. from t
x.append(lambda: i)

Ora i lambda portano una chiusura che fa riferimento a i , ma i è associato a -1 in entrambi i casi, poiché è l'ultimo valore a cui è stato assegnato.

Se vuoi assicurarti che lambda riceva il valore corrente di i , fallo

f(*[lambda u=i: u for i in t])

In questo modo, imponi la valutazione di i al momento della creazione della chiusura.

Modifica : esiste una differenza tra le espressioni del generatore e le comprensioni dell'elenco: quest'ultima perde la variabile loop nell'ambito circostante.

Altri suggerimenti

Lambda acquisisce variabili, non valori, da cui il codice

lambda : i

restituirà sempre il valore a cui è attualmente associato nella chiusura. Quando viene chiamato, questo valore è stato impostato su -1.

Per ottenere ciò che desideri, dovrai catturare il legame effettivo al momento della creazione della lambda, da:

>>> f(*(lambda i=i: i for i in t)) # -> [-1, -1]
[1, -1]
>>> f(*[lambda i=i: i for i in t]) # -> [-1, -1]
[1, -1]

Espressione f = lambda: i è equivalente a:

def f():
    return i

Espressione g = lambda i = i: i è equivalente a:

def g(i=i):
    return i

i è una variabile gratuita nella prima case ed è associato al parametro della funzione nel secondo caso, ovvero in questo caso è una variabile locale. I valori per i parametri predefiniti vengono valutati al momento della definizione della funzione.

L'espressione del generatore è l'ambito racchiuso più vicino (dove è definito i ) per i nell'espressione lambda , quindi i è stato risolto in quel blocco:

f(*(lambda: i for i in (1, -1)) # -> [-1, -1]

i è una variabile locale del blocco lambda i: ... , pertanto l'oggetto a cui fa riferimento è definito in quel blocco:

f(*map(lambda i: lambda: i, (1,-1))) # -> [1, -1]
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top