Perché i lambda di Python sono utili? [chiuso]


929

Sto cercando di capire lambda Python. Lambda è uno di quegli elementi linguistici "interessanti" che nella vita reale dovrebbero essere dimenticati?

Sono sicuro che ci sono alcuni casi limite in cui potrebbe essere necessario, ma data l'oscurità di esso, il potenziale di essere ridefinito nelle versioni future (il mio presupposto basato sulle varie definizioni di esso) e la ridotta chiarezza di codifica - dovrebbe essere evitato?

Questo mi ricorda l'overflow (buffer overflow) dei tipi C - che punta alla variabile superiore e l'overloading per impostare gli altri valori di campo. Sembra una specie di spettacolo tecnico ma un incubo per i programmatori di manutenzione.


261
+1 Buona domanda - cattive assunzioni (oscurità di lambda) =) Cerca di non giudicare le tecniche di programmazione. Valutali e aggiungili al tuo toolkit mentale. Se non ti piacciono, non usarli e preparati a discuterne logicamente senza diventare religioso.
Kieveli,

41
Haskell Rules! Le funzioni Lambda ti danno espressività e potenza di astrazione.
Jonathan Barbero,

11
@JAL Per non parlare di LISP ...
ApproachingDarknessFish

8
@ApproachingDarknessFish "Ah, questa è la parentesi di tuo padre. Un'arma più civile da un'età più civile." - Obi Lisp Kenobi
Fields

Risposte:


1009

Stai parlando delle funzioni lambda ? Piace

lambda x: x**2 + 2*x - 5

Quelle cose sono in realtà abbastanza utili. Python supporta uno stile di programmazione chiamato programmazione funzionale in cui è possibile passare funzioni ad altre funzioni per fare cose. Esempio:

mult3 = filter(lambda x: x % 3 == 0, [1, 2, 3, 4, 5, 6, 7, 8, 9])

imposta mult3 su [3, 6, 9], quegli elementi dell'elenco originale che sono multipli di 3. Questo è più breve (e, si potrebbe obiettare, più chiaro) di

def filterfunc(x):
    return x % 3 == 0
mult3 = filter(filterfunc, [1, 2, 3, 4, 5, 6, 7, 8, 9])

Naturalmente, in questo caso particolare, potresti fare la stessa cosa di una comprensione dell'elenco:

mult3 = [x for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] if x % 3 == 0]

(o anche come range(3,10,3) ), ma ci sono molti altri casi d'uso più sofisticati in cui non è possibile utilizzare una comprensione dell'elenco e una funzione lambda potrebbe essere il modo più breve per scrivere qualcosa.

  • Restituzione di una funzione da un'altra funzione

    >>> def transform(n):
    ...     return lambda x: x + n
    ...
    >>> f = transform(3)
    >>> f(4)
    7

    Questo è spesso usato per creare wrapper di funzioni, come i decoratori di Python.

  • Combinazione di elementi di una sequenza iterabile con reduce()

    >>> reduce(lambda a, b: '{}, {}'.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])
    '1, 2, 3, 4, 5, 6, 7, 8, 9'
  • Ordinamento per chiave alternativa

    >>> sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))
    [5, 4, 6, 3, 7, 2, 8, 1, 9]

Uso le funzioni lambda su base regolare. Mi ci è voluto un po 'di tempo per abituarmi, ma alla fine ho capito che sono una parte molto preziosa della lingua.


26
Adoro gli esempi, molto facili da capire. Ma per la parte ridotta. Se devo implementare questa funzione. Vorrei fare','.join(str(x) for x in [1,2,3,4,5,6,7,8,9])
etlds

3
A proposito, se lo esegui su Python3, devi vedere l'elenco sui risultati del filtro per vedere i valori effettivi, inoltre devi importare riduci da functools
Gerard,

Siamo sicuri della definizione di "programmazione funzionale" di cui sopra? Mi è venuto un po 'di confusione.
stdout,

3
Penso che il punto chiave sia che le lambdafunzioni possano essere anonime (come in tutti i tuoi esempi). Se stai assegnando una lambdafunzione a qualcosa, allora la stai facendo male e dovresti usare definvece
Chris_Rands

1
@zgulser Non è una definizione, è solo un'affermazione su qualcosa che la programmazione funzionale ti consente di fare.
David Z,

377

lambdaè solo un modo elegante di dire function. A parte il suo nome, non c'è nulla di oscuro, intimidatorio o criptico al riguardo. Quando leggi la seguente riga, sostituiscilo lambdacon functionnella tua mente:

>>> f = lambda x: x + 1
>>> f(3)
4

Definisce semplicemente una funzione di x. Alcune altre lingue, come R, lo dicono esplicitamente:

> f = function(x) { x + 1 }
> f(3)
4

Vedi? È una delle cose più naturali da fare in programmazione.


36
Questa è un'ottima descrizione per coloro che provengono da contesti non programmabili (es. Scienze esatte) che rende il significato di lambda molto semplice da capire. Grazie!
Gabriel,

10
Raymond Hettinger ha lamentato il nome in uno dei suoi discorsi e ha detto che ogni confusione avrebbe potuto essere evitata nominandola "fare funzione" invece di "lambda". :-)
ankush981

10
sostituiscilo lambdacon functionnella tua mente e aggiungi returnprima dell'ultima espressione
Ciprian Tomoiagă

4
@AaronMcMillin Try type(lambda x: 3). lambdaespressioni e defdichiarazioni generano entrambi functionoggetti; è solo la sintassi di lambdaun'espressione che limita quali istanze può produrre.
Chepner,

6
@AaronMcMillin Ti manca il mio punto. Solo perché non puoi definire ogni funzione con lambdaun'espressione non significa che il risultato di lambdaun'espressione non è una funzione.
Chepner,

107

Il riepilogo a due righe:

  1. Chiusure : molto utili. Imparali, usali, amali.
  2. Parola lambdachiave di Python : non necessaria, a volte utile. Se ti ritrovi a fare qualcosa di remoto con esso, mettilo via e definisci una vera funzione.

72

Una lambda fa parte di un meccanismo di astrazione molto importante che si occupa di funzioni di ordine superiore. Per una corretta comprensione del suo valore, si prega di guardare lezioni di alta qualità da Abelson e Sussman e leggere il libro SICP

Questi sono problemi rilevanti nel moderno business del software e stanno diventando sempre più popolari.


1
Le espressioni lambda stanno diventando popolari anche in altre lingue (come C #). Non stanno andando da nessuna parte. Leggere sulle chiusure sarebbe un esercizio utile per capire Lambdas. Le chiusure rendono possibile molta magia di programmazione in framework come jQuery.
Dan Esparza,

3
Non confondere lambdale funzioni di prima classe. Python ha un'istruzione estremamente limitata lambda, ma funzioni completamente di prima classe. L'unica differenza che fa è che devi nominare le funzioni che vuoi passare.
Gareth Latty,

59

i lambda sono estremamente utili nella programmazione della GUI. Ad esempio, supponiamo che tu stia creando un gruppo di pulsanti e desideri utilizzare un singolo callback paramaterizzato anziché un callback univoco per pulsante. Lambda ti consente di farlo facilmente:

for value in ["one","two","three"]:
    b = tk.Button(label=value, command=lambda arg=value: my_callback(arg))
    b.pack()

(Nota: sebbene questa domanda stia ponendo una domanda specifica lambda, puoi anche utilizzare functools.partial per ottenere lo stesso tipo di risultato)

L'alternativa è creare un callback separato per ciascun pulsante che può portare a un codice duplicato.


1
Questo è esattamente il motivo per cui ho cercato di capire cosa fosse lambda, ma perché funziona, a me sembra esattamente come chiamare semplicemente la funzione straight ( stackoverflow.com/questions/3704568/… ). Forse è tardi, funziona, ma perché funziona?
Rqomey,

5
@Rqomey: la differenza è che in questo esempio valueè definito in un ciclo; nell'altro esempio il parametro ha sempre avuto un solo valore. Quando si aggiunge qualcosa del genere arg=value, si allega il valore corrente al callback. Senza di essa, si associa un riferimento alla variabile nel callback. Il riferimento conterrà sempre il valore finale della variabile, poiché il callback avviene qualche tempo dopo che il ciclo ha già terminato l'esecuzione.
Bryan Oakley,

1
L'ho appena fatto funzionare ieri, onestamente non riesco a credere quanto sia utile ... Posso creare un menu da uno per loop e un file CSV per la configurazione. Roba davvero utile.
Rqomey,

1
Nota che l'esistenza functools.partial()ti consente di farlo con meno cruft (e senza lambda).
Gareth Latty,

2
partial(my_callback, value)vs lambda arg=value: my_callback(arg)- la lambda ha molto più cruft (assegnazione all'arg e quindi all'utilizzo) ed è meno chiaro quale sia l'intenzione (potresti fare qualcosa di leggermente diverso nella lambda). Le importazioni non sono davvero un problema (hai comunque una pila ed è una volta per file). Il codice è meglio giudicato da quanto bene legge ed partial()è molto più facile da leggere rispetto al lambda.
Gareth Latty,

58

Dubito che lambda andrà via. Vedi il post di Guido sul rinunciare finalmente a provare a rimuoverlo. Vedi anche uno schema del conflitto .

Potresti dare un'occhiata a questo post per ulteriori informazioni sull'affare dietro le funzionalità funzionali di Python: http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html

Curiosamente, la mappa, il filtro e la riduzione delle funzioni che originariamente hanno motivato l'introduzione di lambda e altre caratteristiche funzionali sono state in gran parte sostituite dalla comprensione dell'elenco e dalle espressioni del generatore. In effetti, la funzione di riduzione è stata rimossa dall'elenco delle funzioni integrate in Python 3.0. (Tuttavia, non è necessario inviare reclami sulla rimozione di lambda, mappa o filtro: rimangono. :-)

I miei due centesimi: raramente ne vale la pena per quanto riguarda la chiarezza. Generalmente esiste una soluzione più chiara che non include lambda.


2
si noti che ridurre è ancora impraticabile in Python 3.0. Se lo vuoi davvero, puoi ancora averlo.
Paweł Polewicz,

Penso che il tentativo di Guido riguardasse più la sintassi. Questa persona pensa anche che: cackhanded.com/blog/post/2008/01/24/…
leewz,

38

In Python, lambdaè solo un modo per definire le funzioni in linea,

a = lambda x: x + 1
print a(1)

e..

def a(x): return x + 1
print a(1)

..è l' esatto stessi.

Non c'è niente che tu possa fare con lambda che non puoi fare con una normale funzione: in Python le funzioni sono un oggetto come qualsiasi altra cosa e lambdas semplicemente definisce una funzione:

>>> a = lambda x: x + 1
>>> type(a)
<type 'function'>

Onestamente penso che lambda parola chiave sia ridondante in Python: non ho mai avuto la necessità di usarli (o ne ho visto uno usato dove invece una funzione normale, una comprensione di elenco o una delle molte funzioni incorporate avrebbe potuto essere meglio utilizzate)

Per un esempio completamente casuale, dall'articolo "La lambda di Python è rotta!" :

Per vedere come viene rotto lambda, prova a generare un elenco di funzioni in fs=[f0,...,f9]cui fi(n)=i+n. Primo tentativo:

>>> fs = [(lambda n: i + n) for i in range(10)]
>>> fs[3](4)
13

Direi che, anche se ha funzionato, è orribilmente e "non sinconico", la stessa funzionalità potrebbe essere scritta in innumerevoli altri modi, ad esempio:

>>> n = 4
>>> [i + n for i in range(10)]
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

Sì, non è lo stesso, ma non ho mai visto una causa in cui è stato richiesto di generare un gruppo di funzioni lambda in un elenco. Potrebbe avere senso in altre lingue, ma Python non è Haskell (o Lisp, o ...)

Tieni presente che possiamo usare lambda e ottenere comunque i risultati desiderati in questo modo:

>>> fs = [(lambda n,i=i: i + n) for i in range(10)]
>>> fs[3](4)
7

Modificare:

Ci sono alcuni casi in cui lambda è utile, ad esempio è spesso conveniente quando si collegano segnali in applicazioni PyQt, come questo:

w = PyQt4.QtGui.QLineEdit()
w.textChanged.connect(lambda event: dothing())

Basta fare w.textChanged.connect(dothing)chiamare il dothingmetodo con un eventargomento in più e causare un errore. L'uso di lambda significa che possiamo eliminare in modo ordinato l'argomento senza dover definire una funzione di wrapping.


2
l'argomento "lambda è rotto" è rotto, a causa delle regole di scoping della variabile python funzionano in questo modo, punto. Sarai morso allo stesso modo se hai creato una chiusura all'interno di for-loop.
Antti Haapala,

1
lambda è solo il modo di Python di fornire all'utente una funzione "anonima", come molte altre lingue (ad esempio javascript).
Stefan Gruenwald,

1
La funzione lambda e la funzione adefinite non sono esattamente le stesse. :) Differiscono __name__almeno per campo ...
nperson325681

1
Funziona più di una semplice funzione in linea.
kta,

La tua tesi su "potrebbe avere un senso in un'altra lingua" è strana. O ci sono qualità intrinseche di lambda o no.
Titou,

31

Trovo lambda utile per un elenco di funzioni che fanno lo stesso, ma per circostanze diverse.

Come le regole del plurale Mozilla :

plural_rules = [
    lambda n: 'all',
    lambda n: 'singular' if n == 1 else 'plural',
    lambda n: 'singular' if 0 <= n <= 1 else 'plural',
    ...
]
# Call plural rule #1 with argument 4 to find out which sentence form to use.
plural_rule[1](4) # returns 'plural'

Se dovessi definire una funzione per tutti coloro che alla fine ne impazzirebbero.
Inoltre, non sarebbe carino con nomi di funzioni come plural_rule_1, plural_rule_2ecc. E ne avresti bisogno eval()quando dipendi da un ID di funzione variabile.


1
Questo sembra simile ai brevi incontri che ho avuto finora in F # con la corrispondenza dei modelli e le opzioni. Hai ulteriori informazioni su come utilizzare questa sintassi?
Ken

26

Praticamente tutto ciò che puoi fare con lambdate può fare meglio con le funzioni con nome o con le espressioni di elenco e generatore.

Di conseguenza, per la maggior parte si dovrebbe solo uno di quelli praticamente in qualsiasi situazione (tranne forse per il codice scratch scritto nell'interprete interattivo).


3
"per la maggior parte si dovrebbe solo uno di quelli praticamente in qualsiasi situazione" Periodo. Digitare lambda nell'interprete non è nemmeno così utile.
S. Lott,

11
@Javier sono d'accordo con te se stai parlando di "lambda" il concetto; tuttavia, se parliamo di "lambda" la parola chiave python, allora: 1) le funzioni con nome sono più veloci e possono fare di più (istruzioni + espressioni) quasi ovunque userai lambdas (mappa + filtro) puoi semplicemente generare espressioni o comprendere elenchi che sono più performanti e concisi. Non sto dicendo che le funzioni di prima classe non siano interessanti, ma solo che la parola chiave "lambda" in Python non è buona come usare semplicemente una funzione con nome, tutto qui.
Aaron Maenpaa,

3
lambda mi è stato indispensabile per l'uso con funzioni che accettano argomenti di callback come l'argomento chiave = per ordinare () e sort ()
Rick Copeland,

19
@Rick Non ne dubito, ma la realtà è che quando vedi "lambda" e pensi "zohmygod lambda" e inizi a scrivere codice di schema in Python sarai sicuramente deluso dalle limitazioni dell'espressione lambda di Python. D'altra parte, se inizi a pensare a te stesso "Funzionerà la comprensione di una lista? No. Ciò di cui ho bisogno può essere utile per essere una funzione con nome? No. Va bene: ordinato (xs, key = lambda x: x.name, x.height) ", probabilmente finirai per usare lambda il giusto numero di volte.
Aaron Maenpaa,

4
+1: Non posso sottolineare abbastanza quando si usa una lambda si usa una funzione senza nome . E i nomi hanno un prezioso valore aggiunto intellettuale.
Stephane Rolland,

19

Uso Python da alcuni anni e non ho mai incontrato un caso in cui mi servisse lambda. In realtà, come afferma il tutorial , è solo per lo zucchero sintattico.


8
Sono molto utili quando si sviluppa una GUI usando Python. Spesso, i widget hanno bisogno di un riferimento a una funzione. Se hai bisogno di un widget per chiamare una funzione e passare argomenti, lambda è un modo molto conveniente per farlo.
Bryan Oakley,

1
Qual è il vantaggio rispetto al passaggio di più argomenti nella funzione? nome_funzione (a, b): restituisce a + b anziché usare lambda
dter il

2
non è necessario ma aiuta a scrivere codice più breve e più leggibile in molti casi, esp. in linguaggi dettagliati come Java o C ++
phuclv,

17

Non posso parlare dell'implementazione particolare di lambda di Python, ma in generale le funzioni lambda sono davvero utili. Sono una tecnica di base (forse anche la tecnica) di programmazione funzionale e sono anche molto utili nei programmi orientati agli oggetti. Per alcuni tipi di problemi, sono la soluzione migliore, quindi sicuramente non bisogna dimenticarli!

Ti suggerisco di leggere le chiusure e la funzione mappa (che si collega ai documenti Python, ma esiste in quasi tutte le lingue che supportano costrutti funzionali) per capire perché è utile.


3
Quella roba può essere fatta senza lambda. È solo una grande seccatura.
Brian,

17

La funzione Lambda è un modo non burocratico per creare una funzione.

Questo è tutto. Ad esempio, supponiamo che tu abbia la tua funzione principale e che debba quadrare i valori. Vediamo il modo tradizionale e il modo lambda per farlo:

Modo tradizionale:

def main():
...
...
y = square(some_number)
...
return something

def square(x):
    return x**2

La via lambda:

def main():
...
square = lambda x: x**2
y = square(some_number)
return something

Vedi la differenza?

Le funzioni Lambda vanno molto bene con le liste, come la comprensione delle liste o la mappa. In effetti, la comprensione della lista è un modo "pitonico" per esprimerti usando lambda. Ex:

>>>a = [1,2,3,4]
>>>[x**2 for x in a]
[1,4,9,16]

Vediamo cosa significa ogni elemento della sintassi:

[]: "Dammi un elenco"

x ** 2: "utilizzo di questa funzione appena nata"

per x in a: "in ogni elemento in a"

È conveniente eh? Creare funzioni come questa. Riscriviamolo usando lambda:

>>> square = lambda x: x**2
>>> [square(s) for x in a]
[1,4,9,16]

Ora usiamo map, che è la stessa cosa, ma più neutrale in termini di linguaggio. Maps accetta 2 argomenti:

(i) una funzione

(ii) un iterabile

E ti dà un elenco in cui ogni elemento è la funzione applicata a ciascun elemento dell'iterabile.

Quindi, usando la mappa avremmo:

>>> a = [1,2,3,4]
>>> squared_list = map(lambda x: x**2, a)

Se padroneggi lambda e mappatura, avrai un grande potere di manipolare i dati e in modo conciso. Le funzioni Lambda non sono né oscure né tolgono la chiarezza del codice. Non confondere qualcosa di difficile con qualcosa di nuovo. Una volta che inizi a usarli, lo troverai molto chiaro.


13

Una delle cose belle di ciò lambdache secondo me è sottostimata è che è un modo per rinviare una valutazione per moduli semplici fino a quando il valore è necessario. Lasciatemi spiegare.

Molte routine di libreria sono implementate in modo da consentire a determinati parametri di essere richiamabili (di cui lambda è uno). L'idea è che il valore reale sarà calcolato solo nel momento in cui verrà utilizzato (piuttosto che quando viene chiamato). Un esempio (inventato) potrebbe aiutare a illustrare il punto. Supponiamo di avere una routine che sta per registrare un determinato timestamp. Si desidera che la routine usi l'ora corrente meno 30 minuti. Lo chiameresti così

log_timestamp(datetime.datetime.now() - datetime.timedelta(minutes = 30))

Supponiamo ora che la funzione effettiva venga chiamata solo quando si verifica un determinato evento e vuoi che il timestamp venga calcolato solo in quel momento. Puoi farlo in questo modo

log_timestamp(lambda : datetime.datetime.now() - datetime.timedelta(minutes = 30))

Supponendo che la log_timestamplattina possa gestire i callable in questo modo, lo valuterà quando ne avrà bisogno e otterrai il timestamp in quel momento.

Esistono ovviamente modi alternativi per farlo (usando il operatormodulo per esempio) ma spero di averne parlato.

Aggiornamento : ecco un esempio leggermente più concreto del mondo reale.

Aggiornamento 2 : Penso che questo sia un esempio di ciò che viene chiamato un thunk .


11

Come detto sopra, l'operatore lambda in Python definisce una funzione anonima e in Python le funzioni sono chiusure. È importante non confondere il concetto di chiusure con l'operatore lambda, che è semplicemente metadone sintattico per loro.

Quando ho iniziato a Python qualche anno fa, ho usato moltissimo lambda, pensando che fossero fantastici, insieme alla comprensione delle liste. Tuttavia, ho scritto e devo mantenere un grande sito Web scritto in Python, con l'ordine di diverse migliaia di punti funzione. Ho imparato per esperienza che lambdas potrebbe essere OK con cui prototipare le cose, ma non offre nulla rispetto alle funzioni inline (chiusure denominate) tranne che per salvare alcune sequenze di tasti, o talvolta no.

Fondamentalmente questo si riduce a diversi punti:

  • è più facile leggere software scritto esplicitamente usando nomi significativi. Le chiusure anonime per definizione non possono avere un nome significativo, in quanto non hanno un nome. Questa brevità sembra, per qualche ragione, infettare anche i parametri lambda, quindi vediamo spesso esempi come lambda x: x + 1
  • è più facile riutilizzare le chiusure denominate, in quanto possono essere citate per nome più di una volta, quando esiste un nome a cui fare riferimento.
  • è più facile eseguire il debug del codice che utilizza chiusure denominate anziché lambdas, poiché il nome verrà visualizzato nei traceback e attorno all'errore.

Questa è una ragione sufficiente per arrotondarli e convertirli in chiusure nominate. Tuttavia, ho altri due rancori nei confronti di chiusure anonime.

Il primo rancore è semplicemente che sono solo un'altra parola chiave non necessaria che ingombra la lingua.

Il secondo rancore è più profondo e a livello di paradigma, cioè non mi piace che promuovano uno stile di programmazione funzionale, perché quello stile è meno flessibile del passaggio di messaggi, orientato agli oggetti o stili procedurali, perché il calcolo lambda non è Turing- completo (per fortuna in Python, possiamo ancora uscire da quella restrizione anche all'interno di una lambda). Le ragioni per cui credo che gli lambda promuovano questo stile sono:

  • C'è un ritorno implicito, cioè sembrano che dovrebbero "essere" funzioni.

  • Sono un meccanismo alternativo per nascondere lo stato a un altro meccanismo più esplicito, più leggibile, più riutilizzabile e più generale: i metodi.

Mi sforzo di scrivere Python senza lambda e di rimuovere lambda a vista. Penso che Python sarebbe un linguaggio leggermente migliore senza lambda, ma questa è solo la mia opinione.


1
"... in Python le funzioni sono chiusure". Non è del tutto corretto, come ho capito. Le chiusure sono funzioni, ma le funzioni non sono sempre chiusure. Funzione-> lambda x, y: x + y. Chiusura-> lambda x: lambda y: x + y
0atman

6
"perché il calcolo lambda non è completo di Turing" è chiaramente sbagliato, il calcolo lambda non tipizzato è completo di Turing, ecco perché è così significativo. Puoi ottenere la ricorsione usando il combinatore Y,Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
Antti Haapala,

Inoltre, se si va su Wikipedia per leggere la completezza di Turing, si dice "Un esempio classico è il calcolo lambda".
Antti Haapala,

seriamente - Not Turing complete - questa risposta richiede una modifica o una ritrazione seria.
Tony Suffolk, 66

@ MarcinŁoś Voto positivo perché aderisce a KISS. A titolo di paragone, il libro di K&R menziona che mentre si utilizza l'assegnazione come parte o un'espressione più ampia è più compatta, è spesso meno leggibile. Il trend-wagon dell'utilizzo di schemi di programmazione funzionale è banale e cliché. È sufficiente indicare come possono essere utilizzati, ma è troppo zelante affermare che sono fondamentali per diventare uno sviluppatore competente; completamente soggettivo. Questo argomento è analogo agli sviluppatori C ++ che sostengono che i linguaggi senza classi sono primitivi, inferiori e inadeguati. "Turing-completezza", gli argomenti sono pedanti.
digitato il

11

Le lambda sono in realtà costrutti molto potenti che derivano da idee nella programmazione funzionale, ed è qualcosa che in nessun modo sarà facilmente rivisto, ridefinito o rimosso nel prossimo futuro di Python. Ti aiutano a scrivere codice più potente in quanto ti consente di passare funzioni come parametri, quindi l'idea di funzioni come cittadini di prima classe.

Le lambda tendono a diventare confuse, ma una volta ottenuta una solida comprensione, puoi scrivere un codice pulito ed elegante come questo:

squared = map(lambda x: x*x, [1, 2, 3, 4, 5])

La riga di codice sopra restituisce un elenco dei quadrati dei numeri nell'elenco. Naturalmente, potresti anche farlo come:

def square(x):
    return x*x

squared = map(square, [1, 2, 3, 4, 5])

È ovvio che il codice precedente è più breve, e questo è particolarmente vero se si intende utilizzare la funzione map (o qualsiasi funzione simile che accetta una funzione come parametro) in un solo posto. Questo rende anche il codice più intuitivo ed elegante.

Inoltre, come ha menzionato @David Zaslavsky nella sua risposta, la comprensione della lista non è sempre la strada da percorrere, specialmente se la tua lista deve ottenere valori da un oscuro modo matematico.

Da un punto di vista più pratico, uno dei maggiori vantaggi di lambdas per me recentemente è stato nella GUI e nella programmazione guidata dagli eventi. Se dai un'occhiata ai callback in Tkinter, tutti prendono come argomenti sono l'evento che li ha innescati. Per esempio

def define_bindings(widget):
    widget.bind("<Button-1>", do-something-cool)

def do-something-cool(event):
    #Your code to execute on the event trigger

E se avessi qualche argomento da passare? Qualcosa di semplice come passare 2 argomenti per memorizzare le coordinate di un clic del mouse. Puoi farlo facilmente in questo modo:

def main():
    # define widgets and other imp stuff
    x, y = None, None
    widget.bind("<Button-1>", lambda event: do-something-cool(x, y))

def do-something-cool(event, x, y):
    x = event.x
    y = event.y
    #Do other cool stuff

Ora puoi sostenere che questo può essere fatto usando variabili globali, ma vuoi davvero sbatterti la testa preoccupandoti della gestione della memoria e delle perdite, specialmente se la variabile globale verrà utilizzata in un determinato posto? Sarebbe solo uno stile di programmazione scadente.

In breve, le lambda sono fantastiche e non dovrebbero mai essere sottovalutate. I lambda di Python non sono uguali ai lambda di LISP (che sono più potenti), ma puoi davvero fare un sacco di cose magiche con loro.


Grazie. Non ho capito del tutto il tuo ultimo esempio. Come mai xey sono definiti in entrambi maine do_something_cool? Cosa succede xe ynella funzione? I valori passati sembrano essere sovrascritti immediatamente? Come fa a sapere la funzione event? Potresti aggiungere qualche commento / spiegazione? Grazie
Sanjay Manohar,

@SanjayManohar Sto passando xe ycome argomenti a do-something-coole i loro valori vengono impostati nella funzione per illustrare come è possibile utilizzare lambdas per passare argomenti dove nessuno è previsto. La widget.bindfunzione prevede un eventparametro che identifica l'evento GUI su quel particolare widget. Consiglio di leggere il modello di programmazione di Tkinter per maggiore chiarezza.
varagrawal,

hmm penso di aver capito il modello Tkinter. Ma ancora non capisco bene - passi e x,ypoi fai x=event.x. Questo non sovrascrive il valore che hai passato? E come fa la funzione a sapere cos'è event? Non vedo dove lo passi alla funzione. O è un metodo? Inoltre, sono consentiti segni meno nel nome di una funzione?
Sanjay Manohar,

@SanjayManohar amico, devi leggere su Tkinter e Python. Tkinter trasmette all'oggetto evento la funzione come azione predefinita. Per quanto riguarda il x, y, questo è solo un esempio a scopo illustrativo. Sto cercando di mostrare il potere degli lambda, non di Tkinter. :)
varagrawal,

1
OK ora capisco cosa intendevi: vuoi ricevere la funzione event? in quel caso, il tuo lambda non dovrebbe leggere lambda event: do_something_cool(event,x,y)?
Sanjay Manohar,

8

Le lambda sono profondamente legate allo stile di programmazione funzionale in generale. L'idea che puoi risolvere i problemi applicando una funzione ad alcuni dati e unendo i risultati, è ciò che Google utilizza per implementare la maggior parte dei suoi algoritmi.

I programmi scritti in stile di programmazione funzionale sono facilmente parallelizzabili e quindi stanno diventando sempre più importanti con le moderne macchine multi-core. Quindi in breve, NO, non dovresti dimenticarli.


7

Primi complimenti che sono riusciti a capire lambda. Secondo me questo è un costrutto davvero potente con cui agire. La tendenza attuale verso linguaggi di programmazione funzionale è sicuramente un indicatore del fatto che non dovrebbe essere evitato né sarà ridefinito nel prossimo futuro.

Devi solo pensare un po 'diverso. Sono sicuro che presto lo adorerai. Ma fai attenzione se hai a che fare solo con Python. Poiché la lambda non è una vera chiusura, è in qualche modo "rotta": i pitoni lambda sono rotti


La lambda di Python non è rotta. Ci sono due modi per gestire la gente del posto in lambda. Entrambi hanno vantaggi e svantaggi. Penso che l'approccio adottato da Python (e C #) sia probabilmente controintuitivo a quelli più abituati a linguaggi puramente funzionali, dal momento che con un linguaggio puramente funzionale non penso che l'approccio abbia senso.
Brian,

È davvero controintuitivo. Non sono un programmatore di pitone ma in squittio smalltalk è lo stesso e mi imbatto in questo regolarmente. Quindi anche io lo considererei "rotto" :)
Norbert Hartl,

No, questo non ha nulla a che fare con la controintuitività. È solo che l'ambito lessicale dei nomi delle variabili è quello di una funzione; un ciclo non introduce un ambito lessicale. Le funzioni funzionano anche allo stesso modo in Javascript. Se hai bisogno di un ambito per var, puoi sempre farlo (lambda scopedvar: lambda x: scopedvar + x) ()
Antti Haapala,

6

Sto appena iniziando Python e mi sono imbattuto per primo in Lambda, il che mi ha impiegato un po 'di tempo per capire.

Nota che questa non è una condanna per nulla. Ognuno ha una serie diversa di cose che non arrivano facilmente.

Lambda è uno di quegli elementi linguistici "interessanti" che nella vita reale dovrebbero essere dimenticati?

No.

Sono sicuro che ci sono alcuni casi limite in cui potrebbe essere necessario, ma data l'oscurità,

Non è oscuro. Negli ultimi 2 team su cui ho lavorato, tutti hanno sempre usato questa funzione.

il potenziale che verrà ridefinito nelle versioni future (la mia ipotesi si basa sulle varie definizioni di esso)

Non ho visto proposte serie per ridefinirlo in Python, oltre a fissare la semantica di chiusura alcuni anni fa.

e la ridotta chiarezza della codifica - dovrebbe essere evitata?

Non è meno chiaro, se lo stai usando bene. Al contrario, avere più costrutti linguistici disponibili aumenta la chiarezza.

Questo mi ricorda il trabocco (buffer overflow) dei tipi C - che punta alla variabile superiore e il sovraccarico per impostare gli altri valori di campo ... una specie di dimostrazione tecnica ma incubo del programmatore di manutenzione ..

Lambda è come buffer overflow? Wow. Non riesco a immaginare come stai usando lambda se pensi che sia un "incubo di manutenzione".


5
-1 per avermi fatto leggere (e ad altri) di nuovo l'intera domanda. Nota che altri sono riusciti a rispondere senza farlo.
Paweł Polewicz,

6

Uso lambdas per evitare la duplicazione del codice. Renderebbe la funzione facilmente comprensibile, ad esempio:

def a_func()
  ...
  if some_conditon:
     ...
     call_some_big_func(arg1, arg2, arg3, arg4...)
  else
     ...
     call_some_big_func(arg1, arg2, arg3, arg4...)

Lo sostituisco con un temp lambda

def a_func()
  ...
  call_big_f = lambda args_that_change: call_some_big_func(arg1, arg2, arg3, args_that_change)
  if some_conditon:
     ...
     call_big_f(argX)
  else
     ...
     call_big_f(argY)

5

Ho iniziato a leggere il libro di David Mertz oggi "Text Processing in Python". Mentre ha una descrizione abbastanza concisa di Lambda, gli esempi del primo capitolo combinati con la spiegazione nell'Appendice A li hanno fatti saltare fuori dalla pagina per me (finalmente) e all'improvviso ho capito il loro valore. Questo non vuol dire che la sua spiegazione funzionerà per te e sono ancora in fase di scoperta, quindi non proverò ad aggiungere a queste risposte diverse dalle seguenti: Sono nuovo di Python Sono nuovo di OOP Lambdas è stata una lotta per me Ora che ho letto Mertz, penso di averli presi e li vedo molto utili quanto penso che consentano un approccio più pulito alla programmazione.

Riproduce lo Zen di Python, una delle quali è Semplice è meglio che complessa. Come programmatore non OOP che legge il codice con lambdas (e fino alla comprensione dell'elenco della scorsa settimana) ho pensato : è semplice? . Oggi ho finalmente capito che in realtà queste caratteristiche rendono il codice molto più leggibile e comprensibile dell'alternativa, che è invariabilmente un ciclo di qualche tipo. Mi sono anche reso conto che, come i rendiconti finanziari, Python non è stato progettato per l'utente inesperto, ma piuttosto per l'utente che desidera essere istruito. Non riesco a credere quanto sia potente questa lingua. Quando mi sono reso conto (finalmente) dello scopo e del valore di lambdas, ho voluto elaborare circa 30 programmi e ricominciare da capo inserendo lambdas dove appropriato.


5

Un caso utile per l'utilizzo di lambda è quello di migliorare la leggibilità delle lunghe liste di comprensione . In questo esempio loop_dicè l'abbreviazione di chiarezza, ma immagina di loop_dicessere molto lungo. Se dovessi semplicemente usare un valore semplice che includa iinvece la versione lambda di quel valore otterrai un NameError.

>>> lis = [{"name": "Peter"}, {"name": "Josef"}]

>>> loop_dic = lambda i: {"name": i["name"] + " Wallace" }
>>> new_lis = [loop_dic(i) for i in lis]

>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]

Invece di

>>> lis = [{"name": "Peter"}, {"name": "Josef"}]

>>> new_lis = [{"name": i["name"] + " Wallace"} for i in lis]

>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]

5

Posso farti un esempio in cui avevo davvero bisogno di lambda sul serio. Sto realizzando un programma grafico, in cui l'uso fa clic con il pulsante destro del mouse su un file e gli assegna una delle tre opzioni. Si scopre che in Tkinter (il programma di interfaccia GUI in cui sto scrivendo), quando qualcuno preme un pulsante, non può essere assegnato a un comando che accetta argomenti. Quindi, se ho scelto una delle opzioni e volevo che il risultato della mia scelta fosse:

print 'hi there'

Quindi nessun grosso problema. E se avessi bisogno della mia scelta per avere un dettaglio particolare. Ad esempio, se scelgo la scelta A, chiama una funzione che accetta alcuni argomenti che dipendono dalla scelta A, B o C, TKinter non potrebbe supportarlo. Lamda era l'unica opzione per aggirare questo in realtà ...


2
Bene, presumibilmente avresti potuto farlo def foo...e poi passare fooinvece lambda. È solo più codice e devi trovare un nome.
Jon Coombs il

4

Lo uso abbastanza spesso, principalmente come oggetto null o per associare parzialmente i parametri a una funzione.

Ecco alcuni esempi:

per implementare il modello di oggetti null:

{
    DATA_PACKET: self.handle_data_packets
    NET_PACKET: self.handle_hardware_packets
}.get(packet_type, lambda x : None)(payload)

per l'associazione dei parametri:

diciamo che ho la seguente API

def dump_hex(file, var)
    # some code
    pass

class X(object):
    #...
    def packet_received(data):
        # some kind of preprocessing
        self.callback(data)
    #...

Quindi, quando non voglio scaricare rapidamente i dati ricevuti in un file, lo faccio:

dump_file = file('hex_dump.txt','w')
X.callback = lambda (x): dump_hex(dump_file, x)
...
dump_file.close()

4

Io uso lambda per creare callback che includono parametri. È più pulito scrivere un lambda in una riga piuttosto che scrivere un metodo per eseguire la stessa funzionalità.

Per esempio:

import imported.module

def func():
    return lambda: imported.module.method("foo", "bar")

al contrario di:

import imported.module

def func():
    def cb():
        return imported.module.method("foo", "bar")
    return cb

4

Sono un principiante di pitone, quindi per ottenere un'idea chiara di lambda l'ho confrontato con un ciclo 'for'; in termini di efficienza. Ecco il codice (python 2.7) -

import time
start = time.time() # Measure the time taken for execution

def first():
    squares = map(lambda x: x**2, range(10))
    # ^ Lambda
    end = time.time()
    elapsed = end - start
    print elapsed + ' seconds'
    return elapsed # gives 0.0 seconds

def second():
    lst = []
    for i in range(10):
        lst.append(i**2)
    # ^ a 'for' loop
    end = time.time()
    elapsed = end - start
    print elapsed + ' seconds'
    return elapsed # gives 0.0019998550415 seconds.

print abs(second() - first()) # Gives 0.0019998550415 seconds!(duh)

6
Potresti essere interessato al timeitmodulo, che in genere fornisce risultati più accurati rispetto alla sottrazione di time.time()valori.
Kevin,

2
Hmm, non è necessario riavviare il timer all'inizio di first () e second ()?
qneill

2

Lambda è un costruttore di procedure. Puoi sintetizzare i programmi in fase di esecuzione, anche se la lambda di Python non è molto potente. Nota che poche persone capiscono quel tipo di programmazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.