Lambda funkcijos yra funkcinio prog­ra­ma­vi­mo metodas nuo Python 1.0 versijos. Tačiau pa­sta­rai­siais metais kitos technikos tapo po­pu­lia­res­nės ir iš esmės pakeitė lambda funkcijas. Nepaisant to, vis dar yra keletas spe­cia­li­zuo­tų lambda funkcijų naudojimo atvejų, kuriuos patyrę Python prog­ra­muo­to­jai turėtų žinoti.

Kas yra lambda funkcijos Python kalboje?

Python kalboje lambda funkcija reiškia anoniminę funkciją. Python naudoja raktinį žodį lambda, kad sukurtų lambda funkciją. Lambda išraiška susideda iš raktinio žodžio lambda, po kurio eina argumentų sąrašas, dvitaškis ir viena išraiška. Išraiška pa­tei­kia­ma su ar­gu­men­tais ir įver­ti­na­ma, kai iš­kvie­čia­ma lambda funkcija:

lambda argument: expression

Funkcijos yra pag­rin­di­nė beveik kiek­vie­nos prog­ra­ma­vi­mo kalbos konst­ruk­ci­ja, jos yra ma­žiau­sias pa­kar­to­ti­nai nau­do­ja­mas kodo vienetas. Paprastai Python kalboje funkcijos api­brė­žia­mos naudojant raktinį žodį def. Pa­teik­si­me pavyzdį – kvad­ra­ti­nę funkciją, kuri daugina skaičių iš jo paties:

# Define square function
def square(num):
    return num * num
# Show that it works
assert square(9) == 81
python

def raktinis žodis yra gerai žinomas būdas apibrėžti funkcijas Python kalboje, tačiau šioje kalboje taip pat yra lambda funkcijos. Tai yra ano­ni­mi­nės funkcijos, kurios apibrėžia išraišką su pa­ra­met­rais. Lambda funkcijos gali būti nau­do­ja­mos visur, kur tikimasi funkcijos arba kur ji gali būti priskirta vardui. Čia galite pamatyti lambda išraišką, lygią kvadrato funkcijai:

# Create square function
squared = lambda num: num * num
# Show that it works
assert squared(9) == 81
python

Koks yra skirtumas tarp lambda ir def?

Gali atrodyti keista, kad Python leidžia kurti funkcijas tiek su lambda, tiek su def. Tačiau Lambda nėra jo savybė, o tik dar vienas būdas kurti trumpas funkcijas lokaliai. Kiekviena funkcija, sukurta su lambda, taip pat gali būti sukurta su def. Tačiau at­virkš­čiai tai nėra tiesa.

Sintaksės lygiu lambda ir def yra raktiniai žodžiai. Vienas pag­rin­di­nis skirtumas tarp jų yra Python griežtas teiginių ir išraiškų at­sky­ri­mas. Teiginiai yra kodo vykdymo žingsniai, o išraiškos yra įver­ti­na­mos kaip vertė.

Def pradeda teiginį, tiksliau sudėtinį teiginį, kuris apima kitus teiginius. def teiginyje gali būti tik return teiginiai. return teiginys grąžina reikšmę, kai iš­kvie­čia­ma funkcija, apibrėžta def.

Skir­tin­gai nei def teiginys, lambda pradeda išraišką, kurioje negali būti jokių teiginių. Lambda išraiška priima vieną ar daugiau argumentų ir grąžina anoniminę funkciją. Kai lambda funkcija yra iš­kvie­čia­ma, joje esanti išraiška yra įver­ti­na­ma su per­duo­tais ar­gu­men­tais ir grąžinama.

Kokie yra Python lambda išraiškų ap­ri­bo­ji­mai?

Python są­mo­nin­gai apribojo lambda funkcijų nau­din­gu­mą, nes paprastai geriau yra pavadinti funkcijas. Tai verčia prog­ra­muo­to­jus galvoti apie funkcijos reikšmę ir aiškiai atskirti jos dalis.

Lambda funkcijos negali turėti inst­ruk­ci­jų, skir­tin­gai nei funkcijos, api­brėž­tos raktiniu žodžiu def, kūnas. Todėl lambda funk­ci­jo­je negalima naudoti if, for ir pan. Taip pat negalima sukelti išimties, nes tam rei­ka­lin­gas raise teiginys.

Python kalbos lambda funkcijos gali turėti vieną išraišką, kuri įver­ti­na­ma ją iškvietus. Lambda iš­raiš­ko­je negalima naudoti tipo anotacijų. Šiandien dauguma Python kalbos lambda funkcijų naudojimo atvejų naudoja kitas technikas, pa­vyz­džiui, su­pra­t­imus.

Įvairūs lambda funkcijų naudojimo būdai Python kalboje

Lambda išvestos iš funkcinio prog­ra­ma­vi­mo. Kai kuriose kalbose, pa­vyz­džiui, Ja­vaSc­ript, ano­ni­mi­nės funkcijos plačiai nau­do­ja­mos be spe­cia­laus rak­ta­žo­džio. Python kalboje lambda išraiškos nau­do­ja­mos ne­di­de­lėms funk­ci­joms kurti lokaliai. Toliau ap­žvelg­si­me jų nau­din­giau­sius pri­tai­ky­mus.

Kaip užpildyti aukš­tes­nės eilės funkcijas Python kalboje naudojant lambda išraiškas

Lambdos dažnai nau­do­ja­mos su aukš­tes­nės eilės funk­ci­jo­mis, pvz., map(), filter() ir reduce(). Dėl lambdų ite­ruo­ja­mo elemento elementai gali būti trans­for­muo­ja­mi be ciklų. Aukš­tes­nės eilės funkcijos yra funkcijos, kurios kaip pa­ra­met­rus naudoja funkcijas arba grąžina funkciją.

Funkcija map() priima funkciją ir ite­ruo­ja­mą­jį kaip pa­ra­met­rus. Ji vykdo funkciją kiek­vie­nam ite­ruo­ja­mo­jo elementui. Pa­ban­dy­ki­me su­ge­ne­ruo­ti kvad­ra­ti­nius skaičius. Naudojame funkciją map() ir per­duo­da­me lambda išraišką kaip argumentą, kuris su­ge­ne­ruo­ja kvad­ra­ti­nę funkciją. Kvad­ra­ti­nė funkcija taikoma kiek­vie­nam sąrašo elementui su map():

nums = [3, 5, 7]
# Square numbers using `map()` and `lambda`
squares = map(lambda num: num ** 2, nums)
# Show that it works
assert list(squares) == [9, 25, 49]
python
Note

Nuo Python 3.0 versijos map() ir filter() funkcijos grąžina ite­ruo­ja­mą objektą, o ne sąrašą. list() iš­kvie­ti­mas nau­do­ja­mas assert tei­gi­niuo­se, kad išpakuotų ite­ruo­ja­mus objektus į sąrašą.

Sąrašų su­pra­t­i­mas siūlo mo­der­nes­nį požiūrį į ite­ruo­ja­mų elementų ap­do­ro­ji­mą. Vietoj to, kad naudotume map() ir ge­ne­ruo­tu­me lambda funkciją, galime tie­sio­giai api­bū­din­ti operaciją:

nums = [3, 5, 7]
# Square numbers using list comprehension
squares = [num ** 2 for num in nums]
# Show that it works
assert squares == [9, 25, 49]
python

Funkcija filter() gali būti naudojama ite­ruo­ja­mo elemento ele­men­tams filtruoti. Mes galime išplėsti mūsų pavyzdį, kad būtų ge­ne­ruo­ja­mi tik lyginiai kvad­ra­ti­niai skaičiai:

# List of numbers 1-4
nums = [1, 2, 3, 4]
# Square each number
squares = list(map(lambda num: num ** 2, nums))
# Filter out the even squares
even_squares = filter(lambda square: square % 2 == 0, squares)
# Show that it works
assert list(even_squares) == [4, 16]
python

Pa­tei­kia­me pa­gei­dau­ja­mą metodą, kai nau­do­ja­mas sąrašo su­pra­t­i­mas, kad būtų gautas tas pats re­zul­ta­tas ne­nau­do­jant lambda ir aukš­tes­nės eilės funkcijų. if supratimo dalis naudojama, kad būtų atrinkti lyginiai skaičiai iš generuotų kvad­ra­ti­nių skaičių:

# List of numbers 1-4 squared
squares = [num ** 2 for num in range(1, 5)]
# Filter out the even squares
even_squares = [square for square in squares if square % 2 == 0]
# Show that it works
assert even_squares == [4, 16]
python
Note

Python reduce() funkcija nuo Python 3.0 versijos nėra įtraukta į stan­dar­ti­nę bi­b­lio­te­ką. Ši funkcija yra functools modulyje.

Kaip įgy­ven­din­ti pag­rin­di­nes funkcijas Python kalboje naudojant lambda funkcijas

Su­pra­t­i­mas iš esmės pakeitė kla­si­ki­nės aukš­tes­nės eilės funkcijas map() ir filter() Python kalboje. Tačiau pag­rin­di­nės funkcijos gali būti nau­do­ja­mos norint parodyti visus lambda funkcijų pri­va­lu­mus.

Python pa­ly­gi­ni­mo funkcijos sorted(), min() ir max() veikia ite­ruo­ja­muo­se ob­jek­tuo­se. Kiek­vie­nas ite­ruo­ja­mo objekto elementas yra pa­ly­gi­na­mas, kai funkcija yra iš­kvie­čia­ma. Šios trys funkcijos priima raktinę funkciją kaip ne­pri­va­lo­mą parametrą key. Raktinė funkcija yra iš­kvie­čia­ma kiek­vie­nam elementui ir grąžina raktinę vertę pa­ly­gi­ni­mo ope­ra­ci­jai.

Ap­svars­ty­ki­me šią problemą. Turime aplanką su vaizdo failais, kurių pa­va­di­ni­mai yra susieti su Python sąrašu. Norime su­rū­šiuo­ti sąrašą. Visi failų pa­va­di­ni­mai prasideda skaičiumi img, po kurio eina kitas skaičius:

# List of image file names
images = ['img1', 'img2', 'img30', 'img3', 'img22', 'img100']
python

Jei naudojame Python sorted() funkciją, taikoma lek­si­ko­gra­fi­nė tvarka. Ji traktuoja iš eilės einančius skait­me­nis kaip vieną skaičių. Taigi skaičiai ['1', '2', '100'] yra išdėstomi tvarka ['1', '100', '2']. Re­zul­ta­tas nėra toks, kokio tikimės:

# Sort using lexicographic order
sorted_image = sorted(images)
# Show that it works
assert sorted_image == ['img1', 'img100', 'img2', 'img22', 'img3', 'img30']
python

Mes per­duo­da­me lambda išraišką, kuri sukuria raktinę funkciją, kad už­tik­rin­tu­me teisingą rūšiavimą. Raktinė funkcija išskiria failo vardo skait­me­ni­nę dalį, kuri naudojama kaip raktas sorted():

# Extract numeric component and sort as integers
sorted_image = sorted(images, key=lambda name: int(name[3:]))
# Show that it works
assert sorted_image == ['img1', 'img2', 'img3', 'img22', 'img30', 'img100']
python

Pag­rin­di­nė funkcija naudojama lokaliai ir tik vieną kartą. Nėra būtina apibrėžti pa­pil­do­mos pa­va­din­tos funkcijos. Lambdos yra teisingas būdas kurti pag­rin­di­nes funkcijas. Pa­žvel­ki­me į dar du pa­vyz­džius.

Kaip ir sorted(), įdiegtos Python funkcijos min() ir max() naudoja pa­si­rink­ti­nę raktų funkciją. Šios funkcijos suranda mažiausią ir di­džiau­sią elementą sąraše ar kitame kar­to­ti­nia­me objekte. Ma­žiau­sias ar di­džiau­sias elementas yra api­brė­ži­mo klausimas ir gali būti nurodytas naudojant raktų funkciją.

Aišku, ką reiškia ma­žiau­sias arba di­džiau­sias elementas paprastų verčių sąrašuose, pa­vyz­džiui, skaičių sąraše. Šiuo atveju spe­cia­lios raktinės funkcijos nereikia:

nums = [42, 69, 51, 13]
assert min(nums) == 13
assert max(nums) == 69
python
Note

Jei raktinė funkcija ne­per­duo­da­ma, kaip nu­ma­ty­to­ji naudojama tapatybės funkcija f(x) = x. Tai galima lengvai apibrėžti kaip Python lambda su lambda x: x.

Bet kas, jei kiek­vie­nas ite­ruo­ja­mo elemento elementas apima kelias datas? Įsi­vaiz­duo­ki­me sąrašą, kuriame yra žmonių vardai ir amžius. Kokie yra kri­te­ri­jai, pagal kuriuos spren­džia­ma, kuris min() ir max() yra ma­žiau­sias ir di­džiau­sias elementas? Čia praverčia raktinė funkcija.

Mums reikia pa­vyz­di­nių duomenų, kad galėtume iliust­ruo­ti, kaip veikia pag­rin­di­nės funkcijos. Sukurkime funkciją Person(), kuri veiks kaip konst­ruk­to­rius:

# Constructor function for dict representing a person
def Person(name, age):
    return {'name': name, 'age': age}
# Check that it works as expected
assert Person('Jim', 42) == {'name': 'Jim', 'age': 42}
python

Mes sukuriame žmonių sąrašą naudodami mūsų konst­ruk­to­riaus funkciją:

# Create list of people
people = [person('Jim', 42), person('Jack', 51), person('John', 69)]
python

Rasti vyriausią asmenį naudojant max() skambutį. Tai sukuria raktinę funkciją naudojant lambda išraišką, kuri paima asmens žodyną ir iš jo išskiria amžių kaip pa­ly­gi­ni­mo elementą:

# Find the oldest person
oldest = max(people, key=lambda person: person['age'])
# Check that it works
assert oldest == Person('John', 69)
python

Šis metodas veikia lygiai taip pat ir min() funkcijai. Šiuo atveju api­brė­ši­me pag­rin­di­nę funkciją už min() iš­kvie­ti­mo ribų ir vėl pa­nau­do­si­me lambda išraišką. Tai pagerina skai­to­mu­mą ir yra naudinga, jei pag­rin­di­nė funkcija turi kelis vietinius nau­do­ji­mus:

# Define key function to compare people by age
by_age = lambda person: person['age']
# Find the youngest person
youngest = min(people, key=by_age)
# Check that it works
assert youngest == Person('Jim', 42)
python

Kaip sukurti uždarymus naudojant Python lambda funkcijas

Python lambda taip pat nau­do­ja­mos api­brė­žiant uždarymus. Tai yra funkcijos, kurias sukuria kitos funkcijos ir kurios saugo vertę. Uždarymai gali būti naudojami panašių funkcijų šeimoms kurti. Pa­teik­si­me dažną pavyzdį, kai kuriamos galios funkcijos.

Eks­po­nen­ti­nės funkcijos priima argumentą ir pakelia jį laipsniu. Gerai žinomi pa­vyz­džiai yra kvad­ra­ti­nė funkcija f(x) = x ^ 2 ir kubinė funkcija f(x) = x ^ 3. Bet kokios eks­po­nen­ti­nės funkcijos gali būti ge­ne­ruo­ja­mos kaip uždarymai naudojant konst­ruk­to­riaus funkciją. Naudosime lambda išraišką, o tai reiškia, kad mums nereikės apibrėžti vidinės pa­va­din­tos funkcijos:

# Define constructor function for power functions
def power(n):
    return lambda num: num ** n
# Create square and cubic functions as closures
square = power(2)
cubic = power(3)
# Show that it works
assert square(10) == 100
assert cubic(10) == 1000
python

Kaip naudoti iškart iš­kvie­čia­mą funkcijos išraišką (IIFE) su Python lambda funk­ci­jo­mis

IIFE, tariama „iffy“, yra žinomas Ja­vaSc­ript modelis. Jis apima ano­ni­mi­nės funkcijos api­brė­ži­mą ir jos ne­del­sia­mą vykdymą.

Lambdas gali būti nau­do­ja­mos kaip IIFE, nors dėl Python ap­ri­bo­ji­mų jos nėra labai naudingos. Mums reikia tik įdėti skliaus­te­lius aplink lambda išraišką:

(lambda num: num * num)
python

Ir dar viena pora skliaustų, kuriuose yra ar­gu­men­tas (-ai):

assert (lambda num: num * num)(3) == 9
python
Go to Main Menu