multiple - python property




Perché i lambda di Python sono utili? (18)

Sto cercando di capire i lambda di 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 (la mia ipotesi basata sulle varie definizioni di esso) e la ridotta chiarezza del codice - dovrebbe essere evitato?

Questo mi ricorda di overflow (buffer overflow) di tipi C, che punta alla variabile superiore e overloading per impostare gli altri valori di campo. Sembra una sorta di spettacolarità techie, ma incubo di programmatore di manutenzione.


Sto solo iniziando Python e mi sono imbattuto per la prima volta in Lambda, cosa che mi ha messo un po 'a capire.

Nota che questa non è una condanna di nulla. Ognuno ha un diverso insieme di cose che non vengono 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à di esso,

Non è oscuro. Le ultime 2 squadre su cui ho lavorato, tutti hanno usato questa funzione tutto il tempo.

il potenziale di essere ridefinito in versioni future (la mia ipotesi basata sulle varie definizioni di esso)

Non ho visto proposte serie per ridefinirlo in Python, oltre a fissare la semantica della chiusura qualche anno fa.

e la riduzione della chiarezza del codice - dovrebbe essere evitato?

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

Questo mi ricorda lo straripamento (buffer overflow) dei tipi C - che punta alla variabile superiore e l'overloading per impostare gli altri valori di campo ... una specie di show-show tecnico ma incubatore di coder di manutenzione ..

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


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

Quando ho iniziato a usare Python qualche anno fa, ho usato molto lambda, pensando che fossero fantastici, insieme alle comprensioni delle liste. Tuttavia, ho scritto e devo mantenere un grande sito web scritto in Python, con l'ordine di diverse migliaia di punti di funzione. Ho imparato dall'esperienza che lambdas potrebbe essere OK per prototipare le cose con, ma non offrire nulla rispetto alle funzioni inline (chiamate closures) tranne che per il salvataggio di alcuni key-stokes, o qualche volta no.

Fondamentalmente questo si riduce a diversi punti:

  • è più facile leggere il software che è 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, anche per infettare i parametri lambda, quindi spesso vediamo esempi come lambda x: x + 1
  • è più facile riutilizzare le chiusure denominate, dato che possono essere denominate più volte per nome, quando c'è un nome cui fare riferimento.
  • è più facile eseguire il debug del codice che utilizza le chiusure denominate anziché lambdas, poiché il nome verrà visualizzato nei traceback e attorno all'errore.

Questo è un motivo sufficiente per radunarli e convertirli in chiusure nominate. Tuttavia, nutro altri due rancori contro le chiusure anonime.

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

Il secondo rancore è più profondo e al livello di paradigma, cioè non mi piace che promuovano uno stile di programmazione funzionale, perché quello stile è meno flessibile degli stili di passaggio del messaggio, orientato agli oggetti o procedurale, perché il calcolo lambda non è Turing- completo (per fortuna in Python, possiamo ancora uscire da quella restrizione anche all'interno di una lambda). I motivi per cui sento che Lambdas promuove questo stile sono:

  • C'è un ritorno implicito, cioè sembrano come se dovessero '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 privo di lambda e rimuovere i lambda a vista. Penso che Python sarebbe una lingua leggermente migliore senza lambda, ma questa è solo la mia opinione.


Il riepilogo a due righe:

  1. Closures : molto utili. Impara loro, usali, amali.
  2. lambda chiave lambda di Python: non necessaria, a volte utile. Se ti ritrovi a fare qualcosa di remotamente complesso con esso, metterlo via e definire una funzione reale.

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

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

e..

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

..sono lo stesso identico.

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

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

Onestamente penso che la parola chiave lambda sia ridondante in Python - non ho mai avuto la necessità di usarli (o ne ho visto uno usato in cui una funzione normale, una list-comprehension o una delle molte funzioni builtin avrebbe potuto essere meglio utilizzata)

Per un esempio completamente casuale, dall'articolo "Python's lambda è rotto!" :

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

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

Direi che, anche se funzionasse, è orribile e "non polifonico", 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 è la stessa cosa, ma non ho mai visto una causa in cui sia stato richiesto di generare un gruppo di funzioni lambda in una lista. Potrebbe avere senso in altre lingue, ma Python non è Haskell (o Lisp, o ...)

Si prega di notare 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 nelle applicazioni PyQt, come questo:

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

Facendo semplicemente w.textChanged.connect(dothing) chiamerei il metodo dothing con un argomento event extra e causerebbe un errore. L'uso di lambda significa che possiamo cancellare l'argomento senza dover definire una funzione di avvolgimento.


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

Lambdas tende a confondersi, ma una volta ottenuta una solida comprensione, puoi scrivere un codice elegante e pulito come questo:

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

La riga di codice sopra riportata restituisce un elenco dei quadrati dei numeri nell'elenco. Ofcourse, 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 mappa (o qualsiasi funzione simile che prende una funzione come parametro) in un unico punto. Questo rende anche il codice più intuitivo ed elegante.

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

Da un punto di vista più pratico, uno dei maggiori vantaggi di lambda per me è stato recentemente nella GUI e nella programmazione basata sugli eventi. Se dai un'occhiata ai callback in Tkinter, tutto ciò che prendono come argomenti è l'evento che li ha attivati. 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 degli argomenti da superare? 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 obiettare che questo può essere fatto usando variabili globali, ma vuoi davvero scervellarti preoccupandoti della gestione della memoria e delle perdite, specialmente se la variabile globale sarà usata solo in un posto particolare? Quello sarebbe solo uno stile di programmazione scadente.

In breve, i lambda sono fantastici e non dovrebbero mai essere sottovalutati. I lambda Python non sono uguali a LISP lambdas (che sono più potenti), ma puoi davvero fare un sacco di cose magiche con loro.


Non riesco a parlare con la particolare implementazione di lambda di Python, ma in generale le funzioni lambda sono davvero utili. Sono una tecnica fondamentale (forse anche la tecnica THE) della programmazione funzionale, e sono anche molto utili in programmi orientati agli oggetti. Per alcuni tipi di problemi, sono la soluzione migliore, quindi certamente non dovrebbero essere dimenticati!

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


Primi congrats che sono riusciti a capire lambda. Secondo me questo è un costrutto davvero potente con cui agire. La tendenza in questi giorni verso i linguaggi di programmazione funzionale è sicuramente un indicatore che non dovrebbe essere né evitata né ridefinita nel prossimo futuro.

Devi solo pensare un po 'diverso. Sono sicuro che lo amerai presto. Ma fai attenzione se gestisci solo Python. Perché il lambda non è una vera chiusura, è "spezzato" in qualche modo: i pitoni lambda sono spezzati


Stai parlando delle funzioni lambda ? Piace

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

Queste 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 da mult3 a [3, 6, 9] , quegli elementi della lista originale che sono multipli di 3. Questo è più breve (e, si potrebbe argomentare, 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 lista di comprensione:

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 delle liste e una funzione lambda può 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.

  • Combinare 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 con una 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 'per abituarmi a loro, ma alla fine sono arrivato a capire che sono una parte molto preziosa della lingua.


Trovo lambda utile per un elenco di funzioni che fanno lo stesso, ma per circostanze diverse. Come le regole plurali di 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 quelli a cui impazzirebbe alla fine. Inoltre, non sarebbe bello con nomi di funzioni come plural_rule_1 , plural_rule_2 , ecc. E bisognerebbe eval() quando plural_rule_2 da un ID di funzione variabile.


Una delle cose belle di lambda che secondo me è sottovalutato è che è un modo di posticipare una valutazione per forme semplici fino a quando il valore è necessario. Lasciatemi spiegare.

Molte routine di libreria sono implementate in modo tale da consentire che alcuni parametri siano chiamabili (di cui lambda è uno). L'idea è che il valore effettivo verrà calcolato solo nel momento in cui verrà utilizzato (piuttosto che quando viene chiamato). Un esempio (forzato) potrebbe aiutare a illustrare il punto. Supponiamo di avere una routine su cui registrare un determinato timestamp. Si desidera che la routine utilizzi 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 si desidera 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 log_timestamp possa gestire callables come questo, valuterà questo quando ne avrà bisogno e otterrai il timestamp in quel momento.

Ci sono naturalmente modi alternativi per farlo (usando il modulo operator per esempio) ma spero di aver trasmesso il punto.

Aggiornamento : Here un esempio un po 'più concreto del mondo reale.

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


Uso lambda per evitare la duplicazione del codice. Renderebbe la funzione facilmente comprensibile Es:

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 lambda temp

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)

lambda sono estremamente utili nella programmazione GUI. Ad esempio, diciamo che stai creando un gruppo di pulsanti e che vuoi utilizzare un singolo callback parametrizzato piuttosto che un callback univoco per pulsante. Lambda ti consente di farlo con facilità:

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

(Nota: sebbene questa domanda functools.partial specificamente la domanda su lambda , puoi usare anche functools.partial per ottenere lo stesso tipo di risultato)

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


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 abbia bisogno di 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

Il modo 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 degli elenchi o la mappa. In effetti, la comprensione delle liste è un modo "pitonico" per esprimersi 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 una lista"

x ** 2: "utilizzando questa funzione appena nata"

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

È comodo, vero? Creare funzioni come questa. Riscriviamolo usando lambda:

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

Ora usiamo la mappa, che è la stessa cosa, ma più neutrale rispetto alla lingua. Maps richiede 2 argomenti:

(i) una funzione

(ii) un iterabile

E ti fornisce una lista in cui ogni elemento è la funzione applicata a ciascun elemento del iterabile.

Quindi, usando la mappa avremmo:

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

Se si padroneggiano lambda e mappatura, si avrà 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.


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 cercherò di aggiungere a queste risposte oltre al seguente: Sono nuovo di Python Sono nuovo di OOP Lambdas era una lotta per me Ora che leggo Mertz, penso di averli e li considero molto utili perché penso che permettano un approccio più pulito alla programmazione.

Riproduce lo Zen di Python, una linea di cui è semplice è meglio che complessa. Come programmatore non-OOP che legge il codice con lambda (e fino alla comprensione delle liste della settimana scorsa) ho pensato- Questo è semplice? .Ho finalmente realizzato oggi che in realtà queste caratteristiche rendono il codice molto più leggibile e comprensibile rispetto all'alternativa, che è invariabilmente un loop di qualche tipo. Mi sono anche reso conto che, come le dichiarazioni finanziarie, Python non è stato progettato per l'utente inesperto, ma è progettato per l'utente che vuole essere istruito. Non posso credere quanto sia potente questa lingua. Quando mi sono reso conto (finalmente) dello scopo e del valore di lambda, volevo strappare circa 30 programmi e ricominciare a mettere in lambda, se del caso.


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


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

Ecco alcuni esempi:

per implementare un modello di oggetto nullo:

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

per il collegamento 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 su un file, faccio così:

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

Sono un principiante pitone, quindi per avere 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)

Un caso utile per l'utilizzo di lambda è migliorare la leggibilità delle lunghe liste di comprensione . In questo esempio loop_dicè corta per chiarezza ma immagina di loop_dicessere molto lunga. Se si usasse solo un valore normale che include iinvece della versione lambda di quel valore, si otterrebbe 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'}]




closures