Najczęściej używam funkcji lambda, ale czasami używam funkcji zagnieżdżonych, które wydają się zapewniać to samo zachowanie.
Oto kilka trywialnych przykładów, w których funkcjonalnie robią to samo, jeśli znaleziono jedną z nich w innej funkcji:
Funkcja lambda
>>> a = lambda x : 1 + x
>>> a(5)
6
Funkcja zagnieżdżona
>>> def b(x): return 1 + x
>>> b(5)
6
Czy są zalety używania jednego nad drugim? (Wydajność? Czytelność? Ograniczenia? Spójność? Itp.)
Czy to w ogóle ma znaczenie? Jeśli tak nie jest, narusza to zasadę Pythonic:
Powinien być jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego .
lambda
, ale nie zgadzam się, że jest „bardzo rzadko”, to jest wspólne dla kluczowych funkcji,sorted
lubitertools.groupby
etc., na przykładsorted(['a1', 'b0'], key= lambda x: int(x[1]))
Praktycznie rzecz biorąc, są dla mnie dwie różnice:
Pierwsza dotyczy tego, co robią i co zwracają:
def to słowo kluczowe, które nic nie zwraca i tworzy „nazwę” w lokalnej przestrzeni nazw.
lambda to słowo kluczowe, które zwraca obiekt funkcji i nie tworzy „nazwy” w lokalnej przestrzeni nazw.
Dlatego jeśli chcesz wywołać funkcję, która przyjmuje obiekt funkcji, jedynym sposobem na zrobienie tego w jednym wierszu kodu w Pythonie jest użycie lambda. Nie ma odpowiednika z def.
W niektórych ramach jest to dość powszechne; na przykład często używam Twisted i robię coś takiego
jest dość powszechny i bardziej zwięzły w przypadku lambd.
Druga różnica dotyczy tego, co może robić rzeczywista funkcja.
Na przykład,
działa zgodnie z oczekiwaniami, podczas gdy
jest SyntaxError.
Oczywiście istnieją obejścia - zastąp
print
jesys.stdout.write
lubimport
z__import__
. Ale zazwyczaj w takim przypadku lepiej jest wybrać funkcję.źródło
W tym wywiadzie Guido van Rossum mówi, że żałował, że nie wpuścił „lambdy” do Pythona:
IMHO, Iambdas mogą być czasami wygodne, ale zwykle są wygodne kosztem czytelności. Czy możesz mi powiedzieć, co to robi:
Napisałem to i zajęło mi minutę, zanim to rozgryzłem. To jest z Project Euler - nie powiem, który problem, bo nie znoszę spoilerów, ale działa w 0,124 sekundy :)
źródło
lambda
brak usunięcia w wersji 3.0 był bliski, a Guido nie walczył o jego utrzymanie.Dla n = 1000 mamy trochę czasu na wywołanie funkcji a lambda:
źródło
Występ:
Tworzenie funkcji za pomocą
lambda
jest nieco szybsze niż tworzenie jej za pomocądef
. Różnica wynika zdef
utworzenia wpisu nazwy w tabeli ustawień lokalnych. Wynikowa funkcja ma taką samą szybkość wykonywania.Czytelność:
Funkcje lambda są nieco mniej czytelne dla większości użytkowników Pythona, ale w niektórych okolicznościach są też znacznie bardziej zwięzłe. Rozważ przejście z rutyny niefunkcjonalnej na funkcjonalną:
Jak widać,
lambda
wersja jest krótsza i „łatwiejsza” w tym sensie, że wystarczy dodaćlambda v:
ją do oryginalnej, niefunkcjonalnej wersji, aby przejść do wersji funkcjonalnej. Jest też dużo bardziej zwięzły. Pamiętaj jednak, że wielu użytkowników Pythona będzie zdezorientowanych składnią lambda, więc to, co stracisz na długości i prawdziwej złożoności, może zostać odzyskane przez innych programistów.Ograniczenia:
lambda
funkcje mogą być użyte tylko raz, chyba że są przypisane do nazwy zmiennej.lambda
funkcje przypisane do nazw zmiennych nie mają żadnej przewagi naddef
funkcjami.lambda
funkcje mogą być trudne lub niemożliwe do wytrawienia.def
nazwy funkcji muszą być starannie dobrane, aby były rozsądnie opisowe i unikalne lub przynajmniej w inny sposób nieużywane w zakresie.Konsystencja:
Python w większości unika konwencji programowania funkcjonalnego na rzecz proceduralnej i prostszej semantyki obiektywnej.
lambda
Operator stoi w sprzeczności z tym stronniczości. Ponadto, jako alternatywa dla już rozpowszechnionejdef
,lambda
funkcja dodaje różnorodności do składni. Niektórzy uznaliby to za mniej spójne.Wcześniej istniejące funkcje:
Jak zauważyli inni, wiele zastosowań
lambda
w tej dziedzinie można zastąpić członkamioperator
modułów lub innych modułów. Na przykład:Użycie istniejącej funkcji może w wielu przypadkach zwiększyć czytelność kodu.
Zasada Pythona: „Powinien istnieć jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego”
To jest podobne do pojedynczego źródła doktryny prawdy . Niestety, zasada jednego oczywistego sposobu na zrobienie tego zawsze była bardziej tęsknym dążeniem do Pythona niż prawdziwą zasadą przewodnią. Weź pod uwagę bardzo potężne funkcje tablicowe w Pythonie. Są one funkcjonalnym odpowiednikiem funkcji
map
ifilter
:lambda
idef
są takie same.To kwestia opinii, ale powiedziałbym, że wszystko w języku Python przeznaczone do ogólnego użytku, które w oczywisty sposób niczego nie psuje, jest wystarczające.
źródło
Stosowanie lambdy w stosunku do funkcji regularnej ma jedną zaletę: są tworzone w wyrażeniu.
Istnieje kilka wad:
'<lambda>'
)Oba są również tego samego rodzaju obiektami. Z tych powodów generalnie wolę tworzyć funkcje ze
def
słowem kluczowym zamiast z lambdami.Punkt pierwszy - są to obiekty tego samego typu
Lambda daje ten sam typ obiektu, co zwykła funkcja
Ponieważ lambdy są funkcjami, są obiektami pierwszej klasy.
Zarówno lambdy, jak i funkcje:
Jednak w wyrażeniach lambdowych domyślnie brakuje niektórych rzeczy, które funkcje uzyskują za pośrednictwem pełnej składni definicji funkcji.
A Lamba za
__name__
znaczy'<lambda>'
Lambdy to w końcu funkcje anonimowe, więc nie znają swojego imienia.
Zatem lambda nie mogą być wyszukiwane programowo w ich przestrzeni nazw.
To ogranicza pewne rzeczy. Na przykład
foo
można wyszukać za pomocą serializowanego kodu, podczas gdyl
nie można:Możemy dobrze wyszukać
foo
- ponieważ zna swoją nazwę:Lambdy nie mają adnotacji ani napisów
Zasadniczo lambdy nie są udokumentowane. Przepiszmy,
foo
aby być lepiej udokumentowanym:Teraz foo ma dokumentację:
Zważywszy, że nie mamy tego samego mechanizmu przekazywania tych samych informacji lambdom:
Ale możemy je zhakować na:
Ale prawdopodobnie jest jakiś błąd, który zakłóca wynik pomocy.
Lambdy mogą zwracać tylko wyrażenie
Lambdy nie mogą zwracać złożonych instrukcji, tylko wyrażenia.
Wyrażenia mogą być wprawdzie dość złożone, a jeśli bardzo się postarasz, prawdopodobnie możesz osiągnąć to samo za pomocą lambdy, ale dodatkowa złożoność bardziej szkodzi pisaniu czystego kodu.
Używamy Pythona dla przejrzystości i łatwości konserwacji. Nadużywanie lambd może temu przeciwdziałać.
Tylko góry za lambdas: mogą być tworzone w jednym wyrażeniu
To jedyna możliwa korzyść. Ponieważ możesz utworzyć lambdę za pomocą wyrażenia, możesz utworzyć ją wewnątrz wywołania funkcji.
Utworzenie funkcji wewnątrz wywołania funkcji pozwala uniknąć (niedrogiego) wyszukiwania nazwy w porównaniu z wyszukiwaniem utworzonym gdzie indziej.
Jednak ponieważ Python jest ściśle oceniany, nie ma innego zwiększenia wydajności poza unikaniem wyszukiwania nazwy.
Dla bardzo prostego wyrażenia mógłbym wybrać lambdę.
Zwykle używam również lambd podczas interaktywnego Pythona, aby uniknąć wielu wierszy, gdy to zrobi. Używam następującego formatu kodu, gdy chcę przekazać argument do konstruktora podczas wywoływania
timeit.repeat
:I teraz:
Uważam, że powyższą niewielką różnicę czasu można przypisać wyszukiwaniu nazw w
return_nullary_function
- zwróć uwagę, że jest to bardzo pomijalne.Wniosek
Lambdy są dobre w nieformalnych sytuacjach, w których chcesz zminimalizować liczbę wierszy kodu na rzecz tworzenia osobnych punktów.
Lambdy są złe w bardziej formalnych sytuacjach, w których potrzebujesz jasności dla redaktorów kodu, którzy przyjdą później, zwłaszcza w przypadkach, gdy są one nietrywialne.
Wiemy, że mamy nadawać naszym przedmiotom dobre nazwy. Jak możemy to zrobić, gdy obiekt nie ma nazwy?
Z tych wszystkich powodów generalnie wolę tworzyć funkcje za pomocą
def
zamiast withlambda
.źródło
Zgadzam się z radą nosklo: jeśli chcesz nadać funkcji nazwę, użyj
def
. Rezerwujęlambda
funkcje dla przypadków, w których właśnie przekazuję krótki fragment kodu do innej funkcji, np .:źródło
Zgadzając się z innymi odpowiedziami, czasami jest bardziej czytelny. Oto przykład, w którym się
lambda
przydaje, w przypadku użycia, w którym ciągle napotykam N-wymiardefaultdict
.Oto przykład:
Uważam, że jest to bardziej czytelne niż tworzenie
def
dla drugiego wymiaru. Ma to jeszcze większe znaczenie w przypadku wyższych wymiarów.źródło
from functools import partial; defaultdict(partial(defaultdict, list))
. Przypisz podrzędną nazwę, jeśli chcesz jej użyć więcej niż raz. Ale jeśli nadal napotykasz ten konstrukt, oznacza to, że nie jesteś SUCHY. Uwzględnij to w bibliotece narzędzi. Możesz użyć tej konstrukcji do stworzenia dowolnego n-wymiarowego defaultdict przy użyciu innych functools (lub pętli lub rekursji).Podstawowym zastosowaniem lambdy zawsze były proste funkcje zwrotne oraz mapowanie, zmniejszanie i filtrowanie, które wymagają funkcji jako argumentu. Ze składanymi listami stają się normą, a dodawane dozwolone, jeśli jak w:
trudno sobie wyobrazić prawdziwy przypadek użycia lambdy w codziennym użytkowaniu. W rezultacie powiedziałbym, że unikaj lambdy i twórz funkcje zagnieżdżone.
źródło
Ważnym ograniczeniem wyrażeń lambd jest to, że nie mogą one zawierać niczego poza wyrażeniem. Jest prawie niemożliwe, aby wyrażenie lambda wytworzyło cokolwiek poza trywialnymi skutkami ubocznymi, ponieważ nie może mieć nawet tak bogatej treści jak
def
funkcja ed.Biorąc to pod uwagę, Lua wpłynęła na mój styl programowania w kierunku szerokiego stosowania anonimowych funkcji i zaśmiecam nimi swój kod. Co więcej, myślę o mapowaniu / redukuj jako operatorach abstrakcyjnych w sposób, którego nie uważam za wyrażenia listowe lub generatory, prawie tak, jak w przypadku jawnego odraczania decyzji o implementacji za pomocą tych operatorów.
Edycja: To dość stare pytanie, a moje opinie na ten temat nieco się zmieniły.
Po pierwsze, jestem silnie stronniczy przed przypisywaniem
lambda
wyrażenia do zmiennej; ponieważ python ma specjalną składnię tylko do tego (wskazówka,def
). Oprócz tego wiele zastosowań lambdy, nawet jeśli nie ma nazwy, ma predefiniowane (i bardziej wydajne) implementacje. Na przykład przykład, o którym mowa, można skrócić do just(1).__add__
, bez konieczności zawijania go wlambda
lubdef
. Wiele innych typowych zastosowań mogą być spełnione z jakiejś kombinacjioperator
,itertools
ifunctools
modułów.źródło
(1).__add__
- bezpośrednie wywoływanie metod dunder prawie nigdy nie powinno mieć miejsca. Tysiąclambda
sekund za każde bezpośrednie połączenie alarmowe.(1).__add__
są nieco rzadkie, ale nie zbliżałbym się do „powinien”. bez wątpienia uważam, że ten pierwszy jest znacznie bardziej czytelnylambda x: 1 + x
. Gdybyśmy mieli coś bardziej podobnego do notacji plastrów haskells,(1+)
byłoby świetnie, ale musimy zadowolić się tym, co jest dokładnie tym semantycznie, nazwą metody dunder.Biorąc pod uwagę prosty przykład,
źródło
Jeśli zamierzasz tylko przypisać lambdę do zmiennej w zakresie lokalnym, równie dobrze możesz użyć def, ponieważ jest bardziej czytelny i można go łatwiej rozwinąć w przyszłości:
lub
źródło
from operator import pow;map(pow, someList)
i(a**b for a,b in someList)
są jeszcze bardziej czytelny.Jednym z zastosowań lambd, które znalazłem ... są komunikaty debugowania.
Ponieważ lambdy można oceniać leniwie, możesz mieć taki kod:
zamiast prawdopodobnie drogiego:
który przetwarza ciąg formatu, nawet jeśli wywołanie debugowania nie generuje danych wyjściowych z powodu bieżącego poziomu rejestrowania.
Oczywiście, aby działało zgodnie z opisem, używany moduł logowania musi obsługiwać lambdy jako „parametry leniwości” (tak jak robi to mój moduł logowania).
Ten sam pomysł można zastosować w każdym innym przypadku leniwej oceny w celu tworzenia wartości na żądanie.
Na przykład ten niestandardowy operator trójskładnikowy:
zamiast:
z lambdami oceniane będą tylko wyrażenia wybrane przez warunek, bez lambd oba będą oceniane.
Oczywiście możesz po prostu użyć funkcji zamiast lambd, ale w przypadku krótkich wyrażeń lambdy są (c) odchudzone.
źródło
logging
ma już leniwe formatowanie:log.debug("this is my message: %r", some_data)
będzie formatować tylko wtedy, gdy / jeśli zażądano wiadomości.some_data
może być kosztowne wyrażenie lub wywołanie funkcji / metody.Zgadzam się z nosklo. Nawiasem mówiąc, nawet przy jednorazowym użyciu funkcji wyrzuć , przez większość czasu chcesz po prostu użyć czegoś z modułu operatora.
EG:
Masz funkcję z tym podpisem: myFunction (dane, funkcja zwrotna).
Chcesz przekazać funkcję, która dodaje 2 elementy.
Korzystanie z lambda:
Sposób pytoniczny:
Oczywiście jest to prosty przykład, ale moduł operatora dostarcza wiele rzeczy, w tym ustawiające / pobierające elementy dla list i dict. Bardzo fajny.
źródło
Główną różnicą jest to, że nie można używać
def
funkcji inline, co jest moim zdaniem najwygodniejszym przypadkiem użycialambda
funkcji. Na przykład podczas sortowania listy obiektów:Dlatego sugerowałbym pozostawienie stosowania lambd do tego rodzaju trywialnych operacji, które również nie korzystają z automatycznej dokumentacji dostarczanej przez nazwanie funkcji.
źródło
lambda jest przydatna do generowania nowych funkcji:
źródło