Dlaczego lambda Python są przydatne? [Zamknięte]


928

Próbuję rozgryźć lambda Pythona. Czy lambda jest jednym z tych „interesujących” przedmiotów językowych, o których w prawdziwym życiu należy zapomnieć?

Jestem pewien, że istnieją pewne skrajne przypadki, w których może to być potrzebne, ale biorąc pod uwagę niejasność tego, jego potencjał zostanie ponownie zdefiniowany w przyszłych wydaniach (moje założenie oparte na różnych jego definicjach) i zmniejszoną przejrzystość kodowania - jeśli powinien być unikanym?

Przypomina mi to przepełnienie (przepełnienie bufora) typów C - wskazanie na najwyższą zmienną i przeciążenie, aby ustawić inne wartości pola. To trochę jak pokaz techniki, ale koszmar programisty konserwacji.


261
+1 Dobre pytanie - złe założenia (niejasność lambda) =) Staraj się nie osądzać technik programowania. Oceń je i dodaj do mentalnego zestawu narzędzi. Jeśli ich nie lubisz, nie używaj ich i przygotuj się na ich logiczne omawianie bez stania się religijnym.
Kieveli

41
Zasady Haskell! Funkcje Lambda zapewniają ekspresję i moc abstrakcji.
Jonathan Barbero

11
@JAL Nie wspominając o LISP ...
ApproachingDarknessFish

8
@ApproachingDarknessFish „Ach, to nawias twojego ojca. Bardziej cywilizowana broń z bardziej cywilizowanego wieku”. - Obi Lisp Kenobi
Fields

Odpowiedzi:


1008

Czy mówisz o funkcjach lambda ? Lubić

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

Te rzeczy są właściwie całkiem przydatne. Python obsługuje styl programowania zwany programowaniem funkcjonalnym, w którym można przekazywać funkcje innym funkcjom. Przykład:

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

ustawia mult3na [3, 6, 9]te elementy oryginalnej listy, które są wielokrotnościami 3. Jest to krótsze (i, można się spierać, wyraźniejsze) niż

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

Oczywiście w tym konkretnym przypadku można zrobić to samo, co interpretację listy:

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

(lub nawet jako range(3,10,3)), ale istnieje wiele innych, bardziej wyrafinowanych przypadków użycia, w których nie można użyć rozumienia listy, a funkcja lambda może być najkrótszym sposobem na napisanie czegoś.

  • Zwracanie funkcji z innej funkcji

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

    Jest to często używane do tworzenia opakowań funkcji, takich jak dekoratory Pythona.

  • Łączenie elementów sekwencji powtarzalnej z 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'
  • Sortowanie według alternatywnego klucza

    >>> 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]

Używam regularnie funkcji lambda. Przyzwyczaiłem się do nich, ale w końcu zrozumiałem, że to bardzo cenna część języka.


26
Uwielbiam przykłady, bardzo łatwe do zrozumienia. Ale dla części redukującej. Jeśli muszę wdrożyć tę funkcję. Zrobiłbym','.join(str(x) for x in [1,2,3,4,5,6,7,8,9])
etlds

3
BTW, jeśli uruchomisz to na Python3, musisz wywołać listę wyników filtrów, aby zobaczyć rzeczywiste wartości, a także musisz zaimportować redukcję z funools
Gerard,

Czy jesteśmy pewni powyższej definicji „programowania funkcjonalnego”? Trochę mi to zagmatwało.
stdout

3
Myślę, że kluczową kwestią jest to, że lambdafunkcje mogą być anonimowe (tak jak we wszystkich twoich przykładach). Jeśli przypisanie lambdafunkcji do niczego potem robisz to źle i powinien używać defzamiast
Chris_Rands

1
@zgulser To nie jest definicja, to tylko stwierdzenie o czymś, co pozwala na to funkcjonalne programowanie.
David Z

377

lambdato tylko fantazyjny sposób powiedzenia function. Poza nazwą, nie ma w tym nic tajemniczego, zastraszającego lub tajemniczego. Kiedy czytasz następujący wiersz, zamień lambdana functionw myśl:

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

Określa tylko funkcję x. Niektóre inne języki Rmówią wprost:

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

Zobaczysz? Jest to jedna z najbardziej naturalnych rzeczy do zrobienia w programowaniu.


36
Jest to świetny opis dla osób wywodzących się ze środowisk nieprogramowych (tj. Nauk ścisłych), co sprawia, że ​​znaczenie pojęcia „ lambda bardzo łatwo zrozumieć”. Dzięki!
Gabriel

10
Raymond Hettinger ubolewał nad tym imieniem w jednym ze swoich wystąpień i powiedział, że można uniknąć wszelkich nieporozumień, nazywając go „make function” zamiast „lambda”. :-)
ankush981

10
zamień lambdana functionw myśl i dodaj returnprzed ostatnim wyrażeniem
Ciprian Tomoiagă

4
@AaronMcMillin Try type(lambda x: 3). zarówno lambdawyrażenia, jak i definstrukcje generują functionobiekty; jest to tylko składnia lambdaekspresji limity których przykłady można go wytworzyć.
chepner

6
@AaronMcMillin Nie rozumiesz mnie. To, że nie można zdefiniować każdej funkcji za pomocą lambdawyrażenia, nie oznacza, że ​​wynik lambdawyrażenia nie jest funkcją.
chepner

107

Dwuliniowe podsumowanie:

  1. Zamknięcia : bardzo przydatne. Naucz się ich, używaj ich, kochaj ich.
  2. Słowo lambdakluczowe Pythona : niepotrzebne, czasami przydatne. Jeśli robisz coś zdalnie skomplikowanego, odłóż to i zdefiniuj prawdziwą funkcję.

72

Lambda jest częścią bardzo ważnego mechanizmu abstrakcyjnego, który zajmuje się funkcjami wyższego rzędu. Aby właściwie zrozumieć jego wartość, obejrzyj wysokiej jakości lekcje Abelsona i Sussmana i przeczytaj książkę SICP

Są to istotne problemy w nowoczesnym biznesie oprogramowania i stają się coraz bardziej popularne.


1
Wyrażenia lambda stają się również popularne w innych językach (takich jak C #). Nigdzie się nie wybierają. Czytanie na temat zamknięć byłoby przydatnym ćwiczeniem, aby zrozumieć Lambdas. Zamknięcia umożliwiają wiele magii kodowania w ramach takich jak jQuery.
Dan Esparza

3
Nie myl lambdasi z pierwszorzędnymi funkcjami. Python ma bardzo ograniczoną lambdainstrukcję, ale pełni funkcje pierwszej klasy. Jedyną różnicą jest to, że musisz nazwać funkcje, które chcesz przekazać.
Gareth Latty

59

lambda są niezwykle przydatne w programowaniu GUI. Załóżmy na przykład, że tworzysz grupę przycisków i chcesz użyć pojedynczego sparametryzowanego wywołania zwrotnego zamiast unikalnego wywołania zwrotnego na przycisk. Lambda pozwala to zrobić z łatwością:

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

(Uwaga: chociaż pytanie dotyczy konkretnie tego pytania lambda, możesz także użyć funools.partial aby uzyskać ten sam typ wyniku)

Alternatywą jest utworzenie osobnego wywołania zwrotnego dla każdego przycisku, co może prowadzić do zduplikowania kodu.


1
Właśnie dlatego sprawdziłem, czym jest lambda, ale dlaczego to działa, dla mnie wygląda dokładnie tak samo, jak zwykłe wywołanie funkcji prosto ( stackoverflow.com/questions/3704568/... ). Może jest późno, działa, ale dlaczego działa?
Rqomey

5
@Rqomey: różnica polega na tym, że w tym przykładzie valuejest zdefiniowany w pętli; w drugim przykładzie parametr zawsze miał tylko jedną wartość. Kiedy dodajesz coś podobnego arg=value, dołączasz bieżącą wartość do wywołania zwrotnego. Bez tego powiążesz odwołanie do zmiennej w wywołaniu zwrotnym. Odwołanie zawsze będzie zawierało końcową wartość zmiennej, ponieważ wywołanie zwrotne następuje po pewnym czasie po zakończeniu działania pętli.
Bryan Oakley,

1
Właśnie dostałem to działające wczoraj, szczerze mówiąc, nie mogę uwierzyć, jak przydatne jest to ... Mogę zbudować menu z jednego dla pętli i pliku csv do konfiguracji. Naprawdę przydatne rzeczy.
Rqomey,

1
Zauważ, że istnienie tego functools.partial()pozwala ci to robić z mniejszą ilością cruft (i bez lambda).
Gareth Latty

2
partial(my_callback, value)vs lambda arg=value: my_callback(arg)- lambda ma znacznie więcej cruft (przypisanie do argumentu, a następnie użycie) i mniej jasne jest, co jest intencją (możesz robić coś subtelnie innego w lambda). Importowanie tak naprawdę nie stanowi problemu (i tak masz stos i jest to jeden raz na plik). Kod najlepiej oceniać na podstawie tego, jak dobrze czyta, i partial()jest o wiele łatwiejszy do odczytania niż lambda.
Gareth Latty

58

Wątpię, czy lambda odejdzie. Zobacz post Guido na temat rezygnacji z próby usunięcia go. Zobacz także zarys konfliktu .

Możesz sprawdzić ten post, aby uzyskać więcej informacji na temat umowy dotyczącej funkcji funkcjonalnych Pythona: http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html

Co ciekawe, funkcje mapowania, filtrowania i zmniejszania, które pierwotnie motywowały wprowadzenie lambda i innych funkcji, zostały w dużej mierze zastąpione przez interpretację list i wyrażenia generatorów. W rzeczywistości funkcja zmniejszania została usunięta z listy wbudowanych funkcji w Pythonie 3.0. (Nie trzeba jednak wysyłać skarg dotyczących usunięcia lambdy, mapy lub filtra: zostają. :-)

Moje dwa centy: rzadko, jeśli chodzi o przejrzystość, jest to lambda. Zasadniczo istnieje bardziej przejrzyste rozwiązanie, które nie obejmuje lambda.


2
zauważ, że redukcja jest nadal importowalna w Pythonie 3.0. Jeśli NAPRAWDĘ tego chcesz, nadal możesz go mieć.
Paweł Polewicz

Myślę, że próba Guido polegała bardziej na składni. Ta osoba uważa również, że: cackhanded.com/blog/post/2008/01/24/…
leewz

38

W Pythonie lambdajest to tylko sposób definiowania funkcji wbudowanych,

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

i..

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

.. są dokładnie takie same.

Nic nie można zrobić z lambda, czego nie można zrobić zwykłą funkcją - w Pythonie funkcje są jak wszystko inne, a lambdy po prostu definiują funkcję:

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

Szczerze mówiąc, myślę, że lambdasłowo kluczowe jest zbędne w Pythonie - nigdy nie musiałem ich używać (ani nie widziałem takiego, w którym lepiej byłoby użyć zwykłej funkcji, rozumienia listy lub jednej z wielu wbudowanych funkcji)

Dla zupełnie przypadkowego przykładu z artykułu „lambda Pythona jest zepsuta!” :

Aby zobaczyć, jak łamana jest lambda, spróbuj wygenerować listę funkcji fs=[f0,...,f9]gdzie fi(n)=i+n. Pierwsze podejscie:

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

Twierdziłbym, że nawet gdyby to zadziałało, jest okropnie i „pozbawione pythonic”, ta sama funkcjonalność mogłaby zostać napisana na niezliczone inne sposoby, na przykład:

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

Tak, to nie to samo, ale nigdy nie widziałem przyczyny, w której wymagane byłoby wygenerowanie grupy funkcji lambda na liście. Może to mieć sens w innych językach, ale Python nie jest Haskell (ani Lisp, ani ...)

Pamiętaj, że możemy użyć lambda i nadal osiągnąć pożądane wyniki w ten sposób:

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

Edytować:

Istnieje kilka przypadków, w których lambda jest przydatna, na przykład często jest wygodna podczas podłączania sygnałów w aplikacjach PyQt, takich jak to:

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

Samo wykonanie w.textChanged.connect(dothing)wywołałoby dothingmetodę z dodatkowym eventargumentem i spowodowałoby błąd. Użycie lambda oznacza, że ​​możemy porządnie upuścić argument bez konieczności definiowania funkcji zawijania.


2
twój argument „lambda jest zepsuty” jest zepsuty, ponieważ reguły zakresu zmiennej zmiennej python działają w ten sposób, kropka. Zostaniesz ugryziony w ten sam sposób, jeśli utworzyłeś zamknięcie wewnątrz pętli for.
Antti Haapala

1
lambda jest po prostu sposobem Pythona na zapewnienie użytkownikowi „anonimowej” funkcji, podobnie jak wiele innych języków (np. javascript).
Stefan Gruenwald

1
aZdefiniowane przez ciebie lambda i funkcje nie są dokładnie takie same. :) Różnią się __name__co najmniej według pola ...
nperson325681

1
Działa to nie tylko funkcja wbudowana.
kta

Twój spór o „może mieć sens w innym języku” jest dziwny. Albo istnieją nieodłączne cechy lambdów, albo nie są.
Titou

31

Uważam, że lambda jest przydatna dla listy funkcji, które robią to samo, ale w różnych okolicznościach.

Podobnie jak reguły liczby mnogiej Mozilli :

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'

Gdybyś musiał zdefiniować funkcję dla wszystkich, oszalałbyś do końca.
Nie byłoby też miło z nazwami funkcji, takimi jak plural_rule_1, plural_rule_2itp. I trzeba by eval()tego było, gdy zależy się od identyfikatora funkcji zmiennej.


1
To wygląda podobnie do krótkich spotkań, które do tej pory miałem na F # z dopasowaniem wzorca i opcjami. Czy masz więcej informacji na temat korzystania z tej składni?
Ken

26

Prawie wszystko, co możesz zrobić lambda, możesz zrobić lepiej z nazwanymi funkcjami lub wyrażeniami list i generatorami.

W związku z tym w przeważającej części powinieneś wybrać tylko jedną z nich w praktycznie każdej sytuacji (może z wyjątkiem kodu scratch zapisanego w interaktywnym tłumaczu).


3
„w przeważającej części powinieneś po prostu jeden z nich w zasadzie w każdej sytuacji” Okres. Wpisywanie lambdy w tłumaczu nie jest nawet takie pomocne.
S.Lott,

11
@Javier Zgadzam się z tobą, jeśli mówisz o koncepcji „lambda”; jeśli jednak mówimy o słowie „pyton”, to: 1) nazwane funkcje są szybsze i mogą robić więcej (instrukcje + wyrażenia) niemal wszędzie, gdzie można użyć lambdas (mapa + filtr), można po prostu generować wyrażenia lub listy wyrażeń które są bardziej wydajne i zwięzłe. Nie twierdzę, że funkcje pierwszej klasy nie są fajne, po prostu to, że słowo kluczowe „lambda” w pythonie nie jest tak dobre, jak tylko używanie funkcji nazwanej, to wszystko.
Aaron Maenpaa,

3
lambda jest dla mnie niezbędna do korzystania z funkcji, które pobierają argumenty wywołania zwrotnego, takie jak argument key = argument sort () i sorted ()
Rick Copeland,

19
@Rick Nie wątpię w to, ale rzeczywistość jest taka, że ​​kiedy zobaczysz „lambda” i pomyślisz „zohmygod lambda” i zaczniesz pisać kod schematu w pythonie, z pewnością rozczarujesz się ograniczeniami wyrażenia lambda w pythonie. Z drugiej strony, jeśli zaczniesz myśleć w duchu: „Czy zrozumienie listy zadziała? Nie. Czy to, czego potrzebuję, to skorzystanie z funkcji nazwanej? Nie. Dobra dobrze: posortowane (xs, key = lambda x: x.name, x.height) ”, prawdopodobnie skończysz używać lambda odpowiednią liczbę razy.
Aaron Maenpaa,

4
+1: Nie mogę tego wystarczająco podkreślić, gdy używa się lambda, używa się funkcji bezimiennej . A nazwy mają cenną intelektualną wartość dodaną.
Stephane Rolland

19

Używam Pythona od kilku lat i nigdy nie spotkałem się z przypadkiem, w którym potrzebowałem lambda. Naprawdę, jak samouczek mówi, tylko dla cukru syntaktycznego.


8
bardzo przydatne podczas tworzenia GUI przy użyciu Pythona. Często widżety potrzebują odniesienia do funkcji. Jeśli potrzebujesz widgetu do wywołania funkcji i przekazania argumentów, lambda jest bardzo wygodnym sposobem na zrobienie tego.
Bryan Oakley,

1
Jaka jest przewaga nad przekazywaniem wielu argumentów do funkcji? func_name (a, b): zwraca a + b zamiast lambda
dter

2
nie jest potrzebne, ale pomaga pisać krótszy kod i jest bardziej czytelny w wielu przypadkach, szczególnie. w pełnych językach, takich jak Java lub C ++
phuclv

17

Nie mogę rozmawiać o konkretnej implementacji lambda przez Pythona, ale ogólnie funkcje lambda są naprawdę przydatne. Są podstawową techniką (a może nawet techniką) programowania funkcjonalnego i są również bardzo przydatne w programach obiektowych. W przypadku niektórych rodzajów problemów są najlepszym rozwiązaniem, więc na pewno nie należy zapominać!

Sugeruję przeczytanie na temat zamknięć i funkcji mapy (która prowadzi do dokumentów Pythona, ale istnieje w prawie każdym języku obsługującym konstrukcje funkcjonalne), aby zobaczyć, dlaczego jest to użyteczne.


3
Można tego dokonać bez lambdas. To tylko wielki kłopot.
Brian

17

Funkcja lambda to niebiurokratyczny sposób tworzenia funkcji.

Otóż ​​to. Załóżmy na przykład, że masz swoją główną funkcję i musisz obliczyć wartości. Zobaczmy tradycyjny sposób i sposób lambda, aby to zrobić:

Tradycyjny sposób:

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

def square(x):
    return x**2

Sposób lambda:

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

Zobacz różnicę?

Funkcje lambda bardzo dobrze pasują do list, takich jak listy czy mapy. W rzeczywistości rozumienie listy jest „pytonicznym” sposobem wyrażania siebie za pomocą lambda. Dawny:

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

Zobaczmy, co oznaczają poszczególne elementy składni:

[]: „Daj mi listę”

x ** 2: „przy użyciu tej nowo narodzonej funkcji”

dla x w: „do każdego elementu w”

To wygodne uh? Tworzenie takich funkcji. Przepiszmy go za pomocą lambda:

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

Teraz użyjmy mapy, która jest tym samym, ale bardziej neutralna językowo. Mapy wymagają 2 argumentów:

(i) jedna funkcja

(ii) iterowalne

I daje listę, w której każdy element jest funkcją zastosowaną do każdego elementu iterowalnego.

Korzystając z mapy, mielibyśmy:

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

Jeśli opanujesz lambdas i mapowanie, będziesz miał wielką moc manipulowania danymi w zwięzły sposób. Funkcje Lambda nie są ani niejasne, ani nie usuwają przejrzystości kodu. Nie myl czegoś twardego z czymś nowym. Gdy zaczniesz ich używać, przekonasz się, że jest to bardzo jasne.


13

Jedną z fajnych rzeczy, lambdaktóre moim zdaniem są zaniżone, jest to, że odracza ocenę prostych formularzy, dopóki wartość nie będzie potrzebna. Pozwól mi wyjaśnić.

Wiele procedur bibliotecznych jest zaimplementowanych w taki sposób, że pozwalają na wywołanie niektórych parametrów (z których jednym jest lambda). Chodzi o to, że rzeczywista wartość zostanie obliczona tylko w momencie, w którym zostanie użyta (a raczej w momencie jej wywołania). (Pomyślny) przykład może pomóc zilustrować ten punkt. Załóżmy, że masz procedurę, która miała rejestrować dany znacznik czasu. Chcesz, aby rutyna wykorzystywała bieżący czas minus 30 minut. Można to tak nazwać

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

Załóżmy teraz, że faktyczna funkcja zostanie wywołana tylko wtedy, gdy wystąpi określone zdarzenie i chcesz, aby znacznik czasu był obliczany tylko w tym czasie. Możesz to zrobić w ten sposób

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

Zakładając, że log_timestampporadzi sobie z takimi wywołaniami, oceni to, kiedy będzie tego potrzebować, i otrzymasz znacznik czasu w tym czasie.

Istnieją oczywiście alternatywne sposoby (np. Użycie operatormodułu), ale mam nadzieję, że przekazałem ten punkt.

Aktualizacja : Oto nieco bardziej konkretny przykład ze świata rzeczywistego.

Aktualizacja 2 : Myślę, że jest to przykład czegoś, co nazywa się młotem .


11

Jak wspomniano powyżej, operator lambda w Pythonie definiuje funkcję anonimową, aw funkcjach Pythona są zamknięciami. Ważne jest, aby nie mylić pojęcia zamknięć z operatorem lambda, który jest dla nich jedynie składniowym metadonem.

Kiedy zacząłem w Pythonie kilka lat temu, często używałem lambdów, myśląc, że są fajne, wraz z listami. Napisałem jednak i muszę prowadzić dużą stronę internetową napisaną w języku Python, z rzędu kilku tysięcy punktów funkcyjnych. Nauczyłem się z doświadczenia, że ​​lambda mogą być w porządku przy prototypowaniu, ale nie oferują nic poza funkcjami wbudowanymi (nazwanymi zamknięciami), z wyjątkiem zaoszczędzenia kilku naciśnięć klawiszy, a czasem nie.

Zasadniczo sprowadza się to do kilku punktów:

  • łatwiej jest czytać oprogramowanie, które jest wyraźnie napisane przy użyciu znaczących nazw. Anonimowe zamknięcia z definicji nie mogą mieć znaczącej nazwy, ponieważ nie mają nazwy. Ta zwięzłość wydaje się z jakiegoś powodu również infekować parametry lambda, dlatego często widzimy przykłady takie jak lambda x: x + 1
  • łatwiej jest ponownie używać nazwanych zamknięć, ponieważ można do nich odwoływać się po imieniu więcej niż jeden raz, gdy istnieje nazwa, do której można się do nich odwoływać.
  • łatwiej jest debugować kod, który używa nazwanych zamknięć zamiast lambdas, ponieważ nazwa pojawi się w trackbackach i wokół błędu.

To wystarczający powód, aby je zaokrąglić w górę i przekonwertować na nazwane zamknięcia. Mam jednak dwie inne pretensje do anonimowych zamknięć.

Pierwszą urazą jest to, że są one po prostu kolejnym niepotrzebnym słowem kluczowym zaśmiecającym język.

Druga uraza jest głębsza i na poziomie paradygmatu, tzn. Nie podoba mi się, że promują styl programowania funkcjonalnego, ponieważ ten styl jest mniej elastyczny niż przekazywanie wiadomości, style obiektowe lub proceduralne, ponieważ rachunek lambda nie jest metodą Turinga ukończone (na szczęście w Pythonie nadal możemy przełamać to ograniczenie nawet w lambda). Czuję, że lambdas promują ten styl:

  • Istnieje ukryty zwrot, tzn. Wydaje się, że „powinny” być funkcjami.

  • Stanowią one alternatywny mechanizm ukrywania stanu w stosunku do innego, bardziej wyraźnego, bardziej czytelnego, bardziej wielokrotnego użytku i bardziej ogólnego mechanizmu: metod.

Staram się pisać w języku Python wolnym od lambda i usuwam lambdy na widok. Myślę, że Python byłby nieco lepszym językiem bez lambdas, ale to tylko moja opinia.


1
„... w Pythonie funkcje są zamknięciami”. To nie do końca tak, jak rozumiem. Zamknięcia są funkcjami, ale funkcje nie zawsze są zamknięciami. Funkcja-> lambda x, y: x + y. Zamknięcie-> lambda x: lambda y: x + y
0atman

6
„ponieważ rachunek lambda nie jest zakończony metodą Turinga” jest po prostu błędny, rachunek lambda bez typu JEST Turinga zakończony, dlatego jest on tak znaczący. Rekurencję można uzyskać za pomocą kombinatora Y,Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
Antti Haapala

Co więcej, jeśli ktoś przejdzie do Wikipedii, aby przeczytać o kompletności Turinga, mówi: „Klasycznym przykładem jest rachunek lambda”.
Antti Haapala

serio - Nie ukończono Turinga - ta odpowiedź wymaga poważnej edycji lub wycofania.
Tony Suffolk 66

@ MarcinŁoś Głosowałem za poprawą, ponieważ przestrzega zasad KISS. Dla porównania w książce K&R wspomniano, że chociaż użycie przypisania jako części lub większego wyrażenia jest bardziej zwarte, często jest mniej czytelne. Trendem używania funkcjonalnych wzorców programowania jest banał i banał. Wystarczy określić, w jaki sposób można je wykorzystać, ale nadgorliwe jest stwierdzenie, że mają one ogromne znaczenie, aby zostać kompetentnym deweloperem; całkowicie subiektywne. Ten argument jest analogiczny do programistów C ++, którzy twierdzą, że języki bez klas są prymitywne, gorsze i nieodpowiednie. „Turing-kompletność”, argumenty są pedantyczne.
typedeaf

11

Lambda to tak naprawdę bardzo potężne konstrukcje, które wynikają z pomysłów w programowaniu funkcjonalnym, i jest to coś, co w żadnym wypadku nie będzie łatwe do poprawienia, przedefiniowania lub usunięcia w najbliższej przyszłości Pythona. Pomagają Ci pisać kod, który jest potężniejszy, ponieważ pozwala przekazywać funkcje jako parametry, a tym samym ideę funkcji jako obywateli pierwszej klasy.

Jagnięta często się mylą, ale po uzyskaniu solidnego zrozumienia możesz napisać czysty elegancki kod w następujący sposób:

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

Powyższy wiersz kodu zwraca listę kwadratów liczb na liście. Oczywiście możesz to również zrobić w następujący sposób:

def square(x):
    return x*x

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

Oczywiste jest, że poprzedni kod jest krótszy, a jest to szczególnie prawdziwe, jeśli zamierzasz używać funkcji mapy (lub dowolnej podobnej funkcji, która przyjmuje funkcję jako parametr) tylko w jednym miejscu. Dzięki temu kod jest bardziej intuicyjny i elegancki.

Ponadto, jak wspomniał Dawid Zasławski w swojej odpowiedzi, zrozumienie listy nie zawsze jest właściwą drogą, szczególnie jeśli twoja lista musi uzyskać wartości z niejasnej matematyki.

Z bardziej praktycznego punktu widzenia jedną z największych zalet lambdas było ostatnio GUI i programowanie oparte na zdarzeniach. Jeśli spojrzysz na wywołania zwrotne w Tkinter, wszystko, co biorą za argument, to zdarzenie, które je wywołało. Na przykład

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

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

A co jeśli masz jakieś argumenty do przekazania? Coś tak prostego, jak przekazanie 2 argumentów do przechowywania współrzędnych kliknięcia myszy. Możesz to łatwo zrobić w następujący sposób:

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

Teraz możesz argumentować, że można to zrobić za pomocą zmiennych globalnych, ale czy naprawdę chcesz uderzyć głową, martwiąc się o zarządzanie pamięcią i wyciek, szczególnie jeśli zmienna globalna będzie używana tylko w jednym konkretnym miejscu? To byłby kiepski styl programowania.

Krótko mówiąc, lambdas są niesamowite i nigdy nie należy ich lekceważyć. Jednak lambda Pythona to nie to samo, co lambda LISP (które są mocniejsze), ale naprawdę można z nimi zrobić wiele magicznych rzeczy.


Dzięki. Całkowicie nie zrozumiałem twojego ostatniego przykładu. W jaki sposób xiy są zdefiniowane zarówno w, jak maini w do_something_cool? Co dzieje się xi yw funkcji? Przekazywane wartości wydają się być natychmiast zastępowane? Skąd ta funkcja wie o tym event? Czy możesz dodać jakieś komentarze / wyjaśnienia? Dzięki
Sanjay Manohar,

@SanjayManohar jestem przechodzącej xa yjako argumenty do-something-cooli ich wartości są ustawione w funkcji celu zilustrowania, jak można wykorzystać lambdy przekazywać argumenty gdzie są spodziewane żadne. widget.bindFunkcja oczekuje eventparametr, który identyfikuje zdarzenie GUI na danym widget. Polecam lekturę modelu programowania Tkintera dla większej przejrzystości.
varagrawal 10.04.15

hmm Myślę, że rozumiem model Tkintera. Ale nadal nie do końca rozumiem - zdajesz, x,ya potem rozumiesz x=event.x. Czy to nie zastępuje przekazanej wartości? A skąd funkcja wie, co eventto jest? Nie widzę, gdzie przekazujesz to do funkcji. Czy jest to metoda? Czy dozwolone są także znaki minus w nazwie funkcji?
Sanjay Manohar,

@SanjayManohar, kolego, musisz przeczytać o Tkinterze i Pythonie. Tkinter przekazuje obiekt zdarzenia funkcję jako akcję domyślną. Jeśli chodzi o x, y, to tylko przykład dla celów ilustracyjnych. Próbuję pokazać moc lambdów, a nie Tkintera. :)
varagrawal 15.04.15

1
OK, teraz widzę, co zamierzałeś - chcesz, aby funkcja odbierała event? w takim razie czy twoja lambda nie powinna czytać lambda event: do_something_cool(event,x,y)?
Sanjay Manohar,

8

Lambdas są ogólnie głęboko związane z funkcjonalnym stylem programowania. Pomysł, że możesz rozwiązać problemy, stosując funkcję do niektórych danych i łącząc wyniki, jest tym, czego Google używa do implementacji większości swoich algorytmów.

Programy napisane w funkcjonalnym stylu programowania można łatwo zrównoleglać, a tym samym stają się coraz ważniejsze dzięki nowoczesnym maszynom wielordzeniowym. Krótko mówiąc, NIE, nie powinieneś ich zapomnieć.


7

Pierwsze gratulacje, które udało się dowiedzieć lambda. Moim zdaniem jest to naprawdę potężny konstrukt do działania. Trend w kierunku funkcjonalnych języków programowania jest z pewnością wskaźnikiem, że nie należy go unikać ani nie zostanie on na nowo zdefiniowany w najbliższej przyszłości.

Musisz tylko pomyśleć trochę inaczej. Jestem pewien, że wkrótce to pokochasz. Ale bądź ostrożny, jeśli masz do czynienia tylko z pytonem. Ponieważ lambda nie jest prawdziwym zamknięciem, jest w jakiś sposób „zepsuta”: pytony lambda są zepsute


Lambda Pythona nie jest zepsuta. Istnieją dwa sposoby radzenia sobie z miejscowymi w lambdas. Oba mają zalety i wady. Myślę, że podejście przyjęte przez Pythona (i C #) jest prawdopodobnie sprzeczne z intuicją w stosunku do tych, którzy są bardziej przyzwyczajeni do czysto funkcjonalnych języków, ponieważ w przypadku czysto funkcjonalnego języka nie sądzę, aby takie podejście miało sens.
Brian

Jest to rzeczywiście sprzeczne z intuicją. Nie jestem programistą python, ale w pisaniu smalltalk jest tak samo i regularnie się na to natknę. Nawet ja uważałbym to za „zepsute” :)
Norbert Hartl

Nie, to nie ma nic wspólnego z sprzecznością z intuicją. Po prostu zakres leksykalny nazw zmiennych dotyczy funkcji; pętla nie wprowadza zakresu leksykalnego. Funkcje działają również w Javascript. Jeśli potrzebujesz zakresu dla var, zawsze możesz to zrobić (lambda scopedvar: lambda x: scopedvar + x) ()
Antti Haapala

6

Właśnie zaczynam Pythona i najpierw wpadłem na Lambdę, co zajęło mi trochę czasu.

Zauważ, że to nie jest potępienie czegokolwiek. Każdy ma inny zestaw rzeczy, które nie przychodzą łatwo.

Czy lambda jest jednym z tych „interesujących” przedmiotów językowych, o których w prawdziwym życiu należy zapomnieć?

Nie.

Jestem pewien, że istnieją pewne skrajne przypadki, w których może to być potrzebne, ale biorąc pod uwagę jego niejasność,

To nie jest niejasne. Ostatnie 2 zespoły, nad którymi pracowałem, wszyscy korzystali z tej funkcji przez cały czas.

potencjał jego przedefiniowania w przyszłych wydaniach (moje założenie oparte na różnych jego definicjach)

Nie widziałem żadnych poważnych propozycji przedefiniowania go w Pythonie, poza ustaleniem semantyki zamykania kilka lat temu.

oraz zmniejszona przejrzystość kodowania - czy należy tego unikać?

Nie jest mniej jasne, jeśli używasz go prawidłowo. Wręcz przeciwnie, posiadanie większej liczby dostępnych konstrukcji językowych zwiększa przejrzystość.

Przypomina mi to przepełnienie (przepełnienie bufora) typów C - wskazanie na najwyższą zmienną i przeciążenie, aby ustawić inne wartości pola ... rodzaj pokazu technicznego, ale koszmar kodera konserwacji ...

Lambda jest jak przepełnienie bufora? Łał. Nie mogę sobie wyobrazić, jak używasz lambda, jeśli uważasz, że to „koszmar konserwacji”.


5
-1 za zmuszenie mnie (i innych) do ponownego przeczytania całego pytania. Pamiętaj, że innym udało się odpowiedzieć bez zrobienia tego.
Paweł Polewicz

6

Używam lambdas, aby uniknąć dublowania kodu. Ułatwiłoby to zrozumienie funkcji Np .:

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

Zastępuję to tempem 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

Zacząłem dziś czytać książkę Davida Mertza „Przetwarzanie tekstu w Pythonie”. Chociaż ma dość zwięzły opis Lambdy, przykłady w pierwszym rozdziale w połączeniu z objaśnieniem w Załączniku A sprawiły, że zeskoczyli ze mnie (wreszcie) i nagle zrozumiałem ich wartość. To nie znaczy, że jego wyjaśnienie zadziała dla ciebie i wciąż jestem na etapie odkrywania, więc nie będę próbował dodawać do tych odpowiedzi innych niż następujące: Jestem nowy w Pythonie Jestem nowy w OOP Lambdas były dla mnie walką Teraz, gdy czytam Mertza, myślę, że je dostaję i uważam je za bardzo przydatne, ponieważ uważam, że pozwalają one na czystsze podejście do programowania.

Odtwarza Zen Pythona, którego jedna linia jest prosta, jest lepsza niż złożona. Jako programista inny niż OOP czytający kod za pomocą lambdas (i do końca listy ze zrozumieniem w zeszłym tygodniu) myślałem - to jest proste? . W końcu uświadomiłem sobie dzisiaj, że w rzeczywistości te funkcje sprawiają, że kod jest znacznie bardziej czytelny i zrozumiały niż alternatywa - która zawsze jest pewnego rodzaju pętlą. Uświadomiłem sobie również, że podobnie jak sprawozdania finansowe, Python nie został zaprojektowany dla początkującego użytkownika, a raczej dla użytkownika, który chce się uczyć. Nie mogę uwierzyć, jak potężny jest ten język. Kiedy dotarło do mnie (wreszcie) cel i wartość lambdas, chciałem rozerwać około 30 programów i zacząć od nowa, w stosownych przypadkach, lambdas.


5

Przydatnym przykładem użycia lambdów jest poprawa czytelności długich list . W tym przykładzie loop_dicbrakuje jasności, ale wyobraź sobie, loop_dicże jesteś bardzo długi. Jeśli użyjesz zwykłej wartości, która zawiera izamiast wersji lambda tej wartości, otrzymasz 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'}]

Zamiast

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

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

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

5

Mogę podać przykład, w którym naprawdę potrzebowałem lambda poważnie. Tworzę program graficzny, w którym kliknięcie pliku prawym przyciskiem myszy i przypisanie mu jednej z trzech opcji. Okazuje się, że w Tkinter (program interfejsu GUI, w którym to piszę), kiedy ktoś naciska przycisk, nie można go przypisać do polecenia, które przyjmuje argumenty. Więc jeśli wybrałem jedną z opcji i chciałbym, aby wynikiem mojego wyboru było:

print 'hi there'

Więc nic wielkiego. Ale co, jeśli potrzebuję mojego wyboru, aby mieć konkretny szczegół. Na przykład, jeśli wybiorę opcję A, wywołuje ona funkcję, która przyjmuje argument zależny od wyboru A, B lub C, TKinter nie może tego obsłużyć. Lamda była jedyną opcją na obejście tego ...


2
Cóż, prawdopodobnie mógłbyś to zrobić, def foo...a następnie poddać się foozamiast lambda. To tylko więcej kodu i musisz wymyślić nazwę.
Jon Coombs

4

Używam go dość często, głównie jako obiekt zerowy lub w celu częściowego powiązania parametrów z funkcją.

Oto przykłady:

aby zaimplementować wzorzec obiektu zerowego:

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

dla wiązania parametrów:

powiedzmy, że mam następujący interfejs API

def dump_hex(file, var)
    # some code
    pass

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

Następnie, gdy nie chcę szybko zrzucić otrzymanych danych do pliku, robię to:

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

4

używam lambda do tworzenia wywołań zwrotnych zawierających parametry. Czystsze jest pisanie lambda w jednym wierszu niż pisanie metody wykonywania tej samej funkcjonalności.

Na przykład:

import imported.module

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

w przeciwieństwie do:

import imported.module

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

4

Jestem początkującym w Pythonie, więc aby uzyskać jasne pojęcie o lambda, porównałem go z pętlą „za”; pod względem wydajności. Oto kod (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
Możesz być zainteresowany timeitmodułem, który zazwyczaj daje dokładniejsze wyniki niż odejmowanie time.time()wartości.
Kevin

2
Hmm, czy nie musisz ponownie uruchamiać stopera na początku pierwszego () i drugiego ()?
qneill

2

Lambda jest konstruktorem procedur. Możesz syntetyzować programy w czasie wykonywania, chociaż lambda Pythona nie jest bardzo potężna. Zauważ, że niewiele osób rozumie tego rodzaju programowanie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.