Które z nich jest lepsze w użyciu: funkcje lambda czy funkcje zagnieżdżone („def”)?

102

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 .

Promień
źródło

Odpowiedzi:

106

Jeśli chcesz przypisać nazwę lambdado nazwy, użyj defzamiast tego. defs są po prostu cukrem syntaktycznym dla zadania, więc wynik jest taki sam, są o wiele bardziej elastyczne i czytelne.

lambdas można użyć tylko raz, wyrzuć funkcje, które nie będą miały nazwy.

Jednak ten przypadek użycia jest bardzo rzadki. Rzadko trzeba omijać nienazwane obiekty funkcyjne.

Builtins map()i filter()potrzeby funkcji obiektów, ale listowych i wyrażenia generatorów są na ogół bardziej czytelny niż tych funkcji i może obejmować wszystkie przypadki użycia, bez konieczności lambda.

W przypadkach, gdy naprawdę potrzebujesz małego obiektu funkcyjnego, powinieneś użyć operatorfunkcji modułu, takich jak operator.addzamiastlambda x, y: x + y

Jeśli nadal potrzebujesz niektórych, które lambdanie zostały uwzględnione, możesz rozważyć napisanie def, aby być bardziej czytelnym. Jeśli funkcja jest bardziej złożona niż te w operatormodule, a defjest prawdopodobnie lepsza.

Zatem lambdaprzypadki użycia dobrych rzeczy w świecie rzeczywistym są bardzo rzadkie.

nosklo
źródło
9
Zgadzam się z odpowiedzią na kiedy używać lambda, ale nie zgadzam się, że jest „bardzo rzadko”, to jest wspólne dla kluczowych funkcji, sortedlub itertools.groupbyetc., na przykładsorted(['a1', 'b0'], key= lambda x: int(x[1]))
Chris_Rands
30

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

d.addCallback(lambda result: setattr(self, _someVariable, result))

jest dość powszechny i ​​bardziej zwięzły w przypadku lambd.

Druga różnica dotyczy tego, co może robić rzeczywista funkcja.

  • Funkcja zdefiniowana za pomocą „def” może zawierać dowolny kod Pythona
  • Funkcja zdefiniowana za pomocą `` lambda '' musi obliczać do wyrażenia i dlatego nie może zawierać instrukcji, takich jak print, import, raise, ...

Na przykład,

def p(x): print x

działa zgodnie z oczekiwaniami, podczas gdy

lambda x: print x

jest SyntaxError.

Oczywiście istnieją obejścia - zastąp printje sys.stdout.writelub importz __import__. Ale zazwyczaj w takim przypadku lepiej jest wybrać funkcję.

Thomas Vander Stichele
źródło
23

W tym wywiadzie Guido van Rossum mówi, że żałował, że nie wpuścił „lambdy” do Pythona:

" Q. Co cechą Pythona jesteś najmniej zadowolony z?

Czasami byłem zbyt szybkie w przyjmowaniu wkładów, a później sobie sprawę, że to był błąd. Przykładem może być niektóre z cech funkcjonalnych programowania, takich jak funkcje lambda. Lambda jest słowem kluczowym, które umożliwia utworzenie małej anonimowej funkcji; wbudowane funkcje, takie jak mapowanie, filtrowanie i zmniejszanie, uruchamiają funkcję w typie sekwencji, takim jak lista.

W praktyce nie wyszło to najlepiej. Python ma tylko dwa zakresy: lokalny i globalny. To sprawia, że ​​pisanie funkcji lambda jest bolesne, ponieważ często chcesz uzyskać dostęp do zmiennych w zakresie, w którym została zdefiniowana lambda, ale nie możesz tego zrobić z powodu dwóch zakresów. Jest sposób na obejście tego, ale to coś w rodzaju bałaganu. Często wydaje się znacznie łatwiejsze w Pythonie, aby po prostu użyć pętli for zamiast bawić się funkcjami lambda. mapa i przyjaciele działają dobrze tylko wtedy, gdy jest już wbudowana funkcja, która robi to, co chcesz.

IMHO, Iambdas mogą być czasami wygodne, ale zwykle są wygodne kosztem czytelności. Czy możesz mi powiedzieć, co to robi:

str(reduce(lambda x,y:x+y,map(lambda x:x**x,range(1,1001))))[-10:]

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 :)

Chris Lawlor
źródło
20
Zwróć uwagę, że wywiad jest dość stary, a Python już dawno dodał zagnieżdżone zakresy, co sprawia, że ​​argument, który podaje przeciwko lambdzie, nie ma już znaczenia. Jestem pewien, że nadal żałuje lambdy, ale nie na tyle, aby usunąć ją w Pythonie 3.0.
Thomas Wouters,
10
Naprawdę twój przykład powinien być argumentem przeciwko jednolinijkowemu, a nie lambdom. Ponadto, zamiast redukować za pomocą lambda, należy użyć wbudowanej funkcji sumy: str (sum (map (lambda x: x ** x, range (1001)))) [: - 10]
Triptych
2
@ThomasWouters: Rozumiem, że lambdabrak usunięcia w wersji 3.0 był bliski, a Guido nie walczył o jego utrzymanie.
Ethan Furman
11

Dla n = 1000 mamy trochę czasu na wywołanie funkcji a lambda:

In [11]: def f(a, b):
             return a * b

In [12]: g = lambda x, y: x * y

In [13]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    f(a, b)
   ....:
100 loops, best of 3: 285 ms per loop

In [14]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    g(a, b)
   ....:
100 loops, best of 3: 298 ms per loop

In [15]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    (lambda x, y: x * y)(a, b)
   ....:
100 loops, best of 3: 462 ms per loop
Andy Hayden
źródło
3
Ciekawe, że lambda i zdefiniowane wersje są z grubsza równoważne. Ostatni test zajął więcej czasu, ponieważ Python prawdopodobnie musiał przydzielić miejsce za każdym razem, gdy definiował tę funkcję lambda.
hlin117
Myślę, że ma to sens, ponieważ definicja może odnosić się do zmiennych lokalnych (które mogły ulec zmianie) ... chociaż w przypadku, gdy tak nie jest, jak tutaj, cpython mógłby wykonać lepszą pracę.
Andy Hayden
Użyj dis.dis; Twoje (lambda x, y: x * y) tworzy funkcję w każdej pętli. Jeśli utworzysz lambdę przed pętlą (aka f = lambda x, y: x * y), kod bajtowy wywołania funkcji będzie dokładnie taki sam jak g / f w poprzednim przykładzie, dlatego wydajność lambda jest taka sama jako funkcja def. Zatem lambda lub def to brak wpływu, jeśli używasz tego samego. Wykonaj odwrotność, zadeklaruj funkcję f () w pętli, a następnie wywołaj ją ...
tito
@tito Wierzę, że właśnie to pokazują 3 przykłady z opóźnieniem ...
Andy Hayden,
@tito oh, mówisz, że definiujesz funkcję w pętli, jasne, ale uważam, że to niezwykły wzorzec. Nie jestem pewien, dlaczego to wymagało głosowania przeciw temu komentarzowi ...
Andy Hayden
7

Występ:

Tworzenie funkcji za pomocą lambdajest nieco szybsze niż tworzenie jej za pomocą def. Różnica wynika z defutworzenia 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ą:

# Using non-functional version.

heading(math.sqrt(v.x * v.x + v.y * v.y), math.atan(v.y / v.x))

# Using lambda with functional version.

fheading(v, lambda v: math.sqrt(v.x * v.x + v.y * v.y), lambda v: math.atan(v.y / v.x))

# Using def with functional version.

def size(v):
    return math.sqrt(v.x * v.x + v.y * v.y)

def direction(v):
    return math.atan(v.y / v.x)

deal_with_headings(v, size, direction)

Jak widać, lambdawersja 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.
  • lambdafunkcje przypisane do nazw zmiennych nie mają żadnej przewagi nad deffunkcjami.
  • 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. lambdaOperator stoi w sprzeczności z tym stronniczości. Ponadto, jako alternatywa dla już rozpowszechnionej def, lambdafunkcja 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ń lambdaw tej dziedzinie można zastąpić członkami operatormodułów lub innych modułów. Na przykład:

do_something(x, y, lambda x, y: x + y)
do_something(x, y, operator.add)

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 mapi filter:

[e for e in some_array if some_condition(e)]
filter(some_array, some_condition)

lambdai defsą 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.

Pi Marillion
źródło
7

Bardziej preferowane: funkcje lambda czy funkcje zagnieżdżone ( def)?

Stosowanie lambdy w stosunku do funkcji regularnej ma jedną zaletę: są tworzone w wyrażeniu.

Istnieje kilka wad:

  • bez imienia (tylko '<lambda>')
  • bez dokumentów
  • brak adnotacji
  • brak skomplikowanych instrukcji

Oba są również tego samego rodzaju obiektami. Z tych powodów generalnie wolę tworzyć funkcje ze defsłowem kluczowym zamiast z lambdami.

Punkt pierwszy - są to obiekty tego samego typu

Lambda daje ten sam typ obiektu, co zwykła funkcja

>>> l = lambda: 0
>>> type(l)
<class 'function'>
>>> def foo(): return 0
... 
>>> type(foo)
<class 'function'>
>>> type(foo) is type(l)
True

Ponieważ lambdy są funkcjami, są obiektami pierwszej klasy.

Zarówno lambdy, jak i funkcje:

  • może być przekazywany jako argument (tak samo jak zwykła funkcja)
  • gdy są tworzone w ramach funkcji zewnętrznej, stają się zamknięciem dla lokalności tej funkcji zewnętrznej

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.

>>> l.__name__
'<lambda>'
>>> foo.__name__
'foo'

Zatem lambda nie mogą być wyszukiwane programowo w ich przestrzeni nazw.

To ogranicza pewne rzeczy. Na przykład foomożna wyszukać za pomocą serializowanego kodu, podczas gdy lnie można:

>>> import pickle
>>> pickle.loads(pickle.dumps(l))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <function <lambda> at 0x7fbbc0464e18>: 
attribute lookup <lambda> on __main__ failed

Możemy dobrze wyszukać foo- ponieważ zna swoją nazwę:

>>> pickle.loads(pickle.dumps(foo))
<function foo at 0x7fbbbee79268>

Lambdy nie mają adnotacji ani napisów

Zasadniczo lambdy nie są udokumentowane. Przepiszmy, fooaby być lepiej udokumentowanym:

def foo() -> int:
    """a nullary function, returns 0 every time"""
    return 0

Teraz foo ma dokumentację:

>>> foo.__annotations__
{'return': <class 'int'>}
>>> help(foo)
Help on function foo in module __main__:

foo() -> int
    a nullary function, returns 0 every time

Zważywszy, że nie mamy tego samego mechanizmu przekazywania tych samych informacji lambdom:

>>> help(l)
Help on function <lambda> in module __main__:

<lambda> lambda (...)

Ale możemy je zhakować na:

>>> l.__doc__ = 'nullary -> 0'
>>> l.__annotations__ = {'return': int}
>>> help(l)
Help on function <lambda> in module __main__:

<lambda> lambda ) -> in
    nullary -> 0

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.

>>> lambda: if True: 0
  File "<stdin>", line 1
    lambda: if True: 0
             ^
SyntaxError: invalid syntax

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:

import timeit

def return_nullary_lambda(return_value=0):
    return lambda: return_value

def return_nullary_function(return_value=0):
    def nullary_fn():
        return return_value
    return nullary_fn

I teraz:

>>> min(timeit.repeat(lambda: return_nullary_lambda(1)))
0.24312214995734394
>>> min(timeit.repeat(lambda: return_nullary_function(1)))
0.24894469301216304

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ą defzamiast with lambda.

Aaron Hall
źródło
6

Zgadzam się z radą nosklo: jeśli chcesz nadać funkcji nazwę, użyj def. Rezerwuję lambdafunkcje dla przypadków, w których właśnie przekazuję krótki fragment kodu do innej funkcji, np .:

a = [ (1,2), (3,4), (5,6) ]
b = map( lambda x: x[0]+x[1], a )
Dan Lenski
źródło
3
W większości kombinacji map / lambda możesz zastąpić je listą lub bardziej odpowiednią funkcją. Na przykład „map (suma, a)” lub „[x [0] + x [1] for x in a]”
John Millikin
Tak to prawda. Czasami jednak wolę map (). W większości był to tylko wymyślony przykład użycia funkcji in-line.
Dan Lenski,
dokładnie ... Większość przykładów jest wymyślona, ​​ponieważ ich użycie jest nienaturalne i w większości przypadków istnieją praktyczne lepsze sposoby.
nosklo
5

Zgadzając się z innymi odpowiedziami, czasami jest bardziej czytelny. Oto przykład, w którym się lambdaprzydaje, w przypadku użycia, w którym ciągle napotykam N-wymiar defaultdict.
Oto przykład:

from collections import defaultdict
d = defaultdict(lambda: defaultdict(list))
d['Foo']['Bar'].append(something)

Uważam, że jest to bardziej czytelne niż tworzenie defdla drugiego wymiaru. Ma to jeszcze większe znaczenie w przypadku wyższych wymiarów.

Jonathan
ź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).
DylanYoung
3

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:

x = [f for f in range(1, 40) if f % 2]

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.

apg
źródło
3

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 deffunkcja 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 lambdawyraż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 w lambdalub def. Wiele innych typowych zastosowań mogą być spełnione z jakiejś kombinacji operator, itertoolsi functoolsmodułów.

SingleNegationElimination
źródło
1
(1).__add__- bezpośrednie wywoływanie metod dunder prawie nigdy nie powinno mieć miejsca. Tysiąc lambdasekund za każde bezpośrednie połączenie alarmowe.
Ethan Furman
1
@EthanFurman: Cóż, z mojego doświadczenia wynika, że ​​wezwania natury (1).__add__są nieco rzadkie, ale nie zbliżałbym się do „powinien”. bez wątpienia uważam, że ten pierwszy jest znacznie bardziej czytelny lambda 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.
SingleNegationElimination
2
  • Czas obliczeń.
  • Funkcja bez nazwy.
  • Aby osiągnąć jedną funkcję i wiele funkcji użyj.

Biorąc pod uwagę prosty przykład,

# CREATE ONE FUNCTION AND USE IT TO PERFORM MANY OPERATIONS ON SAME TYPE OF DATA STRUCTURE.
def variousUse(a,b=lambda x:x[0]):
    return [b(i) for i in a]

dummyList = [(0,1,2,3),(4,5,6,7),(78,45,23,43)]
variousUse(dummyList)                           # extract first element
variousUse(dummyList,lambda x:[x[0],x[2],x[3]]) # extract specific indexed element
variousUse(dummyList,lambda x:x[0]+x[2])        # add specific elements
variousUse(dummyList,lambda x:x[0]*x[2])        # multiply specific elements
bhargav patel
źródło
1

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:

fun = lambda a, b: a ** b # a pointless use of lambda
map(fun, someList)

lub

def fun(a, b): return a ** b # more readable
map(fun, someList)
za dużo php
źródło
Zarówno from operator import pow;map(pow, someList)i (a**b for a,b in someList)są jeszcze bardziej czytelny.
InQβ
1

Jednym z zastosowań lambd, które znalazłem ... są komunikaty debugowania.

Ponieważ lambdy można oceniać leniwie, możesz mieć taki kod:

log.debug(lambda: "this is my message: %r" % (some_data,))

zamiast prawdopodobnie drogiego:

log.debug("this is my message: %r" % (some_data,))

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:

def mif(condition, when_true, when_false):
    if condition:
         return when_true()
    else:
         return when_false()

mif(a < b, lambda: a + a, lambda: b + b)

zamiast:

def mif(condition, when_true, when_false):
    if condition:
         return when_true
    else:
         return when_false

mif(a < b, a + a, b + b)

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.

Glushiator
źródło
1
NB loggingma już leniwe formatowanie: log.debug("this is my message: %r", some_data)będzie formatować tylko wtedy, gdy / jeśli zażądano wiadomości.
j08lue
Metoda lambda @ j08lue pomija ocenę wszystkiego w przypadku, gdy dane wyjściowe debugowania nie są generowane, w przypadku, gdy pokazane some_datamoże być kosztowne wyrażenie lub wywołanie funkcji / metody.
Glushiator
0

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:

myFunction(data, (lambda x, y : x + y))

Sposób pytoniczny:

import operator
myFunction(data, operator.add)

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.

e-satis
źródło
-1

Główną różnicą jest to, że nie można używać deffunkcji inline, co jest moim zdaniem najwygodniejszym przypadkiem użycia lambdafunkcji. Na przykład podczas sortowania listy obiektów:

my_list.sort(key=lambda o: o.x)

Dlatego sugerowałbym pozostawienie stosowania lambd do tego rodzaju trywialnych operacji, które również nie korzystają z automatycznej dokumentacji dostarczanej przez nazwanie funkcji.

Ali Rasim Kocal
źródło
-2

lambda jest przydatna do generowania nowych funkcji:

>>> def somefunc(x): return lambda y: x+y
>>> f = somefunc(10)
>>> f(2)
12
>>> f(4)
14
chrapliwy
źródło