Funkcje Lambda w Pythonie: składnia, rzeczywiste zastosowania i kiedy ich nie używać

  1. Strona główna
  2. Blog
  3. Rozwój oprogramowania

Rozwój oprogramowania

Funkcje Pythona Lambda: Składnia, rzeczywiste zastosowania i kiedy ich nie używać

Lambda to niewielka funkcja, którą możesz zapisać w jednym wierszu, dokładnie tam, gdzie jej potrzebujesz. Poznaj składnię, miejsca, w których lambdy naprawdę pomagają, pułapkę, która łapie doświadczonych programistów i kiedy normalna funkcja jest po prostu lepsza.

8 min czytania
Funkcje lambda w Pythonie: składnia, rzeczywiste zastosowania i kiedy ich nie używać

Najważniejsze

  • lambda to anonimowa funkcja ograniczona do jednego wyrażenia.
  • Najlepiej używać go jako krótkiego argumentu, szczególnie key dla sorted, min i max.
  • Zrozumienie listy jest zwykle jaśniejsze niż map lub filter z lambdą.
  • Jeśli przypiszesz lambdę do nazwy, zamiast tego napisz def.

Musisz posortować produkty według ceny. Napisanie osobnej funkcji nazwanej tylko po to, by powiedzieć „użyj ceny”, wydaje się być dużą ceremonią. Funkcje lambda w Pythonie umożliwiają zdefiniowanie tego małego fragmentu logiki bezpośrednio tam, gdzie go używasz.

Lambdy są przydatne, ale łatwo je też nadużywać. Ten przewodnik pokazuje, gdzie naprawdę pomagają, a gdzie utrudniają czytanie kodu. Każdy przykład uruchomiliśmy w Pythonie 3.13 i pokazane dane wyjściowe pochodzą z tego uruchomienia.

Co to jest lambda?

Lambda to funkcja bez nazwy, zapisywana za pomocą słowa kluczowego lambda:

lambda arguments: expression

Pobiera dowolną liczbę argumentów i automatycznie zwraca wartość pojedynczego wyrażenia. Nie ma słowa kluczowego return ani treści instrukcji.

square = lambda x: x * x
print(square(4))                     # 16

print((lambda a, b=10: a + b)(5))    # 15

Druga linia definiuje lambdę z domyślnym argumentem i natychmiast ją wywołuje. Rzadko pisałbyś to w prawdziwym kodzie, ale pokazuje to, że lambda jest zwykłym obiektem funkcyjnym.

lambda vs def

Te dwa tworzą funkcje, które zachowują się tak samo:

square = lambda x: x * x

def square_def(x):
    return x * x

print(square(4), square_def(4))                 # 16 16
print(square.__name__, square_def.__name__)     # <lambda> square_def

Spójrz na nazwiska. Każda lambda nazywa się po prostu <lambda>, więc komunikaty o błędach i dzienniki nie mogą powiedzieć, która z nich się nie powiodła. Jest to główny powód, dla którego przewodniki po stylach, takie jak PEP 8, zalecają def, gdy chcesz nadać funkcji nazwę.

Funkcja lambda def
Imię Anonimowy Nazwany
Ciało Jedno wyrażenie Dowolna liczba stwierdzeń
Wróć Niejawne Wyraźne return
Dokumentacja i wskazówki dotyczące typu Nieobsługiwane Obsługiwane
Czytelne ślady Pokazy <lambda> Pokazuje nazwę
Najlepsze dla Krótkie, rzucające się w oczy argumenty Wszystko inne

Sortowanie za pomocą klucza: najlepsze wykorzystanie

Funkcje takie jak sorted, min i max akceptują funkcję key, która decyduje, co należy porównać. Tutaj świecą lambdy:

products = [("pen", 10), ("bag", 900), ("book", 250)]

sorted(products, key=lambda p: p[1])
# [('pen', 10), ('book', 250), ('bag', 900)]

max(products, key=lambda p: p[1])
# ('bag', 900)

Aby posortować według kilku rzeczy, zwróć krotkę. Tutaj ludzie są sortowani według wieku, najpierw najstarsi, a następnie według imienia:

people = [{"name": "Asha", "age": 31}, {"name": "Ben", "age": 25},
          {"name": "Dev", "age": 31}]

[p["name"] for p in sorted(people, key=lambda p: (-p["age"], p["name"]))]
# ['Asha', 'Dev', 'Ben']

Znak minus odwraca kolejność tylko liczby. Czasami w ogóle nie potrzebujesz lambdy, ponieważ istniejąca funkcja już wykonuje to zadanie. Porównaj sortowanie domyślne z sortowaniem nieuwzględniającym wielkości liter:

names = ["Asha", "ben", "Chitra", "dev"]

sorted(names)                  # ['Asha', 'Chitra', 'ben', 'dev']
sorted(names, key=str.lower)   # ['Asha', 'ben', 'Chitra', 'dev']

Domyślnie wszystkie słowa pisane wielkimi literami są umieszczane na pierwszym miejscu. Przekazanie str.lower rozwiązuje ten problem bez użycia lambdy. Moduł operator oferuje podobne pomoce, takie jak itemgetter(1) dla lambda p: p[1].

mapa i filtr

map stosuje funkcję do każdego elementu, a filter zachowuje elementy, dla których zwraca wartość true. Obydwa działają z lambdami, ale porównują każdy ze zrozumieniem listy:

nums = [1, 2, 3, 4, 5, 6]

list(map(lambda n: n * 10, nums))      # [10, 20, 30, 40, 50, 60]
[n * 10 for n in nums]                 # [10, 20, 30, 40, 50, 60]

list(filter(lambda n: n % 2 == 0, nums))   # [2, 4, 6]
[n for n in nums if n % 2 == 0]            # [2, 4, 6]

Wyniki są identyczne, a większość programistów Pythona uważa, że zrozumienie jest łatwiejsze do odczytania. Zauważ też, że map i filter zwracają leniwe iteratory, więc potrzebujesz list(), aby zobaczyć wartości. Nasz przewodnik po rozumieniu list w Pythonie szczegółowo opisuje ten styl. map nadal dobrze czyta się z istniejącą nazwaną funkcją, jak w map(str.strip, lines).

zmniejszyć

functools.reduce łączy elementy w jedną wartość, niosąc bieżący wynik:

from functools import reduce

reduce(lambda acc, n: acc + n, nums, 0)   # 21
sum(nums)                                 # 21

W przypadku typowych zadań, takich jak sumy, użyj wbudowanych opcji, takich jak sum, max lub any. Zachowaj reduce w rzadszych przypadkach i rozważ zwykłą pętlę, jeśli lambda zacznie wyglądać na skomplikowaną.

Warunki w lambdzie

Nie możesz użyć instrukcji if w lambdzie, ale możesz użyć wyrażenia warunkowego:

label = lambda total: "large" if total >= 1000 else "small"

label(1200), label(300)
# ('large', 'small')

Jeden warunek jest w porządku. Gdy zaczniesz je zagnieżdżać, czytelnicy będą musieli ciężko pracować, co jest wyraźnym sygnałem, aby przejść na def ze zwykłymi if instrukcjami.

Lambdy zwracające funkcje

Funkcja może utworzyć i zwrócić lambdę, która zapamiętuje wartość z otoczenia:

def multiplier(n):
    return lambda x: x * n

double = multiplier(2)
double(7)   # 14

Dzieje się tak dzięki zamknięciom, które wyjaśniono w innym języku w naszym artykule na temat zamknięć JavaScript. Python functools.partial oferuje inny sposób wstępnego wypełniania argumentów.

Pułapka późno wiążąca

To w końcu łapie prawie wszystkich. Stworzyliśmy trzy lambdy w pętli, oczekując, że każda zwróci swój własny numer:

funcs = [lambda: i for i in range(3)]
[f() for f in funcs]

# [2, 2, 2]

Wszystkie trzy zwracają 2. Lambda nie przechwytuje wartości z i podczas jej tworzenia. Wyszukuje zmienną, gdy jest ona wywoływana i do tego czasu pętla się kończy, pozostawiając i na poziomie 2. Zwykle rozwiązaniem jest przechwycenie wartości jako argumentu domyślnego, ponieważ wartości domyślne są oceniane w momencie definicji:

funcs = [lambda i=i: i for i in range(3)]
[f() for f in funcs]

# [0, 1, 2]

Nie jest to specyficzne dla lambd, ponieważ def wewnątrz pętli zachowuje się w ten sam sposób. Po prostu pojawia się częściej w przypadku lambd, ponieważ często są one tworzone w pętlach, na przykład podczas dołączania wywołań zwrotnych przycisków.

Wskazówka: Jeśli potrzebujesz funkcji dla każdego elementu, zastanów się, czy w ogóle potrzebujesz wielu funkcji. Często pojedyncza funkcja, która przyjmuje element jako argument, jest jaśniejsza i całkowicie pozwala uniknąć pułapki.

Tabele przeglądowe małych funkcji

Lambdy doskonale pasują do słownika, który odwzorowuje nazwy na małe operacje:

ops = {
    "add": lambda a, b: a + b,
    "sub": lambda a, b: a - b,
}

ops["sub"](10, 3)   # 7

Może to zastąpić długi łańcuch if i elif. Przewodnik Słownik Pythona omawia więcej wzorców słownikowych, a moduł operator udostępnia już operator.add i operator.sub.

Granice lambd

  • Tylko jedno wyrażenie. Żadnych przypisań z =, żadnych pętli i żadnych try bloków.
  • Brak oświadczeń. Pisanie lambda x: return x kończy się niepowodzeniem przy SyntaxError, co potwierdził nasz test.
  • Brak dokumentów i wskazówek dotyczących typów. Narzędzia i czytelnicy otrzymują mniejszą pomoc.
  • Trudniejsze debugowanie. Błędy wskazują na <lambda>, a nie na pomocną nazwę.

Oczywiście lambdy nadal mogą zgłaszać wyjątki. Obsługa tych funkcji działa tak samo, jak w przypadku dowolnej funkcji, zgodnie z opisem w Obsługa wyjątków w Pythonie.

Kiedy nie używać lambdy

Sytuacja Lepszy wybór
Przypisanie go do nazwy def
Logika potrzebuje więcej niż jednej linii def
Przekształcanie lub filtrowanie listy Rozumienie listy
Sumowanie lub znajdowanie maksimum sum, max, min
Pobieranie przedmiotu lub atrybutu operator.itemgetter lub attrgetter
Ta sama lambda pojawia się w kilku miejscach Nazwana funkcja, którą możesz przetestować

Ten ostatni punkt ma znaczenie. Warto przetestować logikę, którą warto ponownie wykorzystać, a nazwaną funkcję znacznie łatwiej przetestować, jak pokazuje nasz samouczek dotyczący testów Pythona.

Podsumowanie

Dobra lambda jest na tyle krótka, że ​​można ją przeczytać na pierwszy rzut oka i użyta raz, zwykle jako argument. Klawisze sortowania są klasycznym przykładem. Aby sprawdzić własny kod, wyszukaj = lambda i zamień go w nazwane funkcje. Następnie spójrz na dowolne map lub filter z lambdą i sprawdź, czy zrozumienie czyta się lepiej.

Najczęstsze pytania

Co to jest funkcja lambda w Pythonie?

Jest to mała anonimowa funkcja utworzona za pomocą słowa kluczowego lambda. Pobiera argumenty i zwraca wartość pojedynczego wyrażenia, bez nazwy i instrukcji return.

Czy lambda w Pythonie może mieć wiele linii?

Nie. Lambda jest ograniczona do jednego wyrażenia. Możesz podzielić go na linie w nawiasach, ale nadal nie może zawierać instrukcji, więc użyj def dla bardziej złożonej logiki.

Czy mogę użyć if else w lambdzie?

Możesz użyć wyrażenia warunkowego, takiego jak lambda x: „duży”, jeśli x > 10, w przeciwnym razie „mały”. Instrukcja if z blokiem jest niedozwolona.

Czy lambdy są szybsze niż normalne funkcje?

Nie sensownie. Obydwa tworzą ten sam rodzaj obiektu funkcyjnego. Wybierz między nimi ze względu na czytelność, a nie wydajność.

Czy powinienem używać mapy z lambdą czy ze zrozumieniem listy?

Większość programistów Pythona preferuje rozumienie list ze względu na czytelność. map jest rozsądna, jeśli masz już nazwaną funkcję, taką jak map(str.strip,lines).

Ucz się dalej

Pracuj z Stack Quora

Potrzebujesz pomocy przy testowaniu, WordPressie lub SEO?

Pomagamy zespołom dostarczać lepsze oprogramowanie i rozwijać ich witryny. Powiedz nam, nad czym pracujesz, a my zaproponujemy jasny następny krok.

Czytaj dalej

Więcej poradników na testowanie, sztuczna inteligencja i nowoczesny rozwój

Podobał Ci się ten artykuł? Wybierz temat i przejdź bezpośrednio do naszych najnowszych tutoriali.

Sztuczna inteligencja

Wyjaśnienie halucynacji AI: dlaczego modele językowe tworzą rzeczy i jak je zmniejszyć

Wyjaśniono halucynacje AI: czym są, dlaczego powstają w modelach językowych, typowe typy, jak je zredukować za pomocą uziemień i podpowiedzi oraz pr…

Przeczytaj artykuł →
DevOps

Wyjaśnienie zmiennych środowiskowych: pliki .env, sekrety i konfiguracja wykonana prawidłowo

Zmienne środowiskowe wyjaśnione na przykładach Pythona, które przeprowadziliśmy: ich odczytywanie i ustawianie, dlaczego każda wartość jest ciągiem …

Przeczytaj artykuł →
Tworzenie oprogramowania

Wyjaśnienie ograniczenia szybkości interfejsu API: algorytmy, nagłówki i obsługa błędów 429

Ograniczanie szybkości API wyjaśnione za pomocą przeprowadzonej przez nas symulacji: zasobnik tokenów, stałe okno, przesuwane okno, 429 odpowiedzi, …

Przeczytaj artykuł →
Automatyzacja testów

Wyśmiewanie w Pythonie: unittest.mock, patch i błędy, które sprawiają, że testy kłamią

Wyśmiewanie w Pythonie za pomocą unittest.mock, przetestowane: Mock i zwracana wartość, efekt uboczny, łatanie tam, gdzie używana jest nazwa, specyf…

Przeczytaj artykuł →
Testowanie oprogramowania

Wyjaśnienie zasięgu kodu: pokrycie linii i oddziału oraz co naprawdę oznacza 100%

Wyjaśnienie pokrycia kodu za pomocą prawdziwego pliku cover.py: pokrycie linii, gałęzi i warunków, przeczytanie raportu, dlaczego 100% pokrycia może…

Przeczytaj artykuł →
Bazy danych i SQL

DELETE vs TRUNCATE vs DROP w SQL: różnice, wycofywanie i kiedy używać każdego z nich

DELETE vs TRUNCATE vs DROP wyjaśnione za pomocą przetestowanego SQL: co każdy usuwa, wycofywanie, wyzwalacze, resetowanie tożsamości, prędkość i czy…

Przeczytaj artykuł →
Bazy danych i SQL

Wyjaśnienie widoków SQL: tworzenie, używanie i unikanie pułapek wraz z przykładami

Widoki SQL wyjaśnione za pomocą zapytań, które uruchomiliśmy: tworzenie widoku, wyniki na żywo, ukrywanie kolumn, wydajność, widoki z możliwością ak…

Przeczytaj artykuł →
Tworzenie oprogramowania

Interfejs TypeScript a typ: rzeczywiste różnice, testowane za pomocą kompilatora

Interfejs TypeScript a typ, sprawdzony z prawdziwym kompilatorem: co oba mogą zrobić, co tylko jeden, łączenie deklaracji, rozszerzenia a przecięcia…

Przeczytaj artykuł →
Tworzenie oprogramowania

Python *args i **kwargs wyjaśnione: elastyczne funkcje z przejrzystymi przykładami

Python *args i **kwargs wyjaśnione za pomocą uruchomionego przez nas kodu: pakowanie i rozpakowywanie, kolejność parametrów, argumenty zawierające t…

Przeczytaj artykuł →
Tworzenie oprogramowania

Funkcje Lambda w Pythonie: składnia, rzeczywiste zastosowania i kiedy ich nie używać

Funkcje lambda w Pythonie wyjaśnione za pomocą uruchomionego przez nas kodu: składnia, sortowanie za pomocą klucza, mapa i filtr, domknięcia, pułapk…

Przeczytaj artykuł →
Sztuczna inteligencja

Kim są agenci AI? Jak one działają, dzięki prostej pętli agenta, którą możesz uruchomić

Kim są agenci AI? Prosty przewodnik po pętli agenta, narzędziach, pamięci i poręczach, z małą pętlą w Pythonie, którą uruchomiliśmy, prawdziwymi zag…

Przeczytaj artykuł →
DevOps

Monitorowanie a obserwowalność: prawdziwa różnica z logami, wskaźnikami i śladami

Wyjaśnienie monitorowania a obserwowalności: znane i nieznane awarie, dzienniki, metryki i ślady, opis incydentu przy kasie, złote sygnały, OpenTele…

Przeczytaj artykuł →
DevOps

Woluminy platformy Docker a mocowania powiązań: utrwalanie danych kontenera we właściwy sposób

Wyjaśniono woluminy Dockera a montowanie powiązań: dlaczego dane kontenera znikają, nazwane woluminy, montowanie powiązań, tmpfs, przykłady tworzeni…

Przeczytaj artykuł →
Automatyzacja testów

TDD vs BDD: kluczowe różnice, jedna funkcja zbudowana w obie strony i kiedy używać każdej z nich

TDD vs BDD wyjaśnione za pomocą jednej funkcji rabatowej zbudowanej w obie strony: refaktoryzacja czerwono-zielona z uruchomionym przez nas kodem, s…

Przeczytaj artykuł →
Tworzenie oprogramowania

Git merge vs rebase: różnice, przykłady i kiedy czego używać

Git merge vs rebase wyjaśnione na prawdziwym wyniku logu, z tabelą porównawczą, złotą zasadą rebase i bezpiecznym procesem pracy zespołu.

Przeczytaj artykuł →
Tworzenie oprogramowania

Python list comprehension: składnia, przykłady i kiedy jej unikać

Python list comprehension wyjaśnione: składnia, filtrowanie, if-else, zagnieżdżone pętle, zmierzone czasy i sytuacje, w których zwykła pętla for jes…

Przeczytaj artykuł →
Bazy danych i SQL

SQL JOIN – wyjaśnienie z przykładami (Inner, Left, Right, Full)

Zrozum złączenia SQL krok po kroku na przykładowych tabelach i zapytaniach: INNER, LEFT, RIGHT, FULL, CROSS i SELF, plus typowe błędy i wskazówki wy…

Przeczytaj artykuł →