Lambda funkcijas ir bijušas fun­kcio­nā­lās prog­ram­mē­ša­nas metode kopš Python 1.0. Tomēr pēdējos gados citas metodes ir ieguvušas lielāku po­pu­la­ri­tā­ti un lielā mērā aiz­stā­ju­šas lambdas. Tomēr joprojām ir daži spe­cia­li­zē­ti lambdas lietojumi, par kuriem pie­re­dzē­ju­šiem Python prog­ram­mē­tā­jiem būtu jāzina.

Kas ir lambda funkcijas Python?

Python valodā lambda funkcija attiecas uz anonīmu funkciju. Python izmanto at­slēg­vār­du lambda, lai izveidotu lambda funkciju. Lambda izteiksme sastāv no at­slēg­vār­da lambda, kam seko argumentu saraksts, defise un viens iz­teik­smes elements. Izteiksme tiek no­dro­ši­nā­ta ar ar­gu­men­tiem un izvērtēta, kad tiek izsaukta lambda funkcija:

lambda argument: expression

Funkcijas ir gandrīz katras prog­ram­mē­ša­nas valodas pa­mat­kons­truk­ci­ja, un tās ir mazākās atkārtoti iz­man­to­ja­mās koda vienības. Parasti funkcijas Python valodā tiek definētas ar at­slēg­vār­du def. Kā piemēru parādīsim kvadrāta funkciju, kas reizinā skaitli ar sevi:

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

def at­slēg­vārds ir labi pazīstams veids, kā definēt funkcijas Python, bet šajā valodā ir arī lambdas. Tās ir anonīmas funkcijas, kas definē izteiksmi ar pa­ra­met­riem. Lambdas var izmantot visur, kur ir ne­pie­cie­ša­ma funkcija vai kur to var piešķirt vārdam. Šeit var redzēt lambda izteiksmi, kas atbilst kvadrāta funkcijai:

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

Kāda ir atšķirība starp lambda un def?

Var šķist dīvaini, ka Python ļauj izveidot funkcijas gan ar lambda, gan ar def. Tomēr Lambda nav tā paša funkcija, bet gan tikai vēl viens veids, kā izveidot īsas funkcijas lokāli. Katru funkciju, kas izveidota ar lambda, var izveidot arī ar def. Tomēr otrādi tas tā nav.

Sin­tak­tis­kā līmenī lambda un def ir abi at­slēg­vār­di. Viena no gal­ve­na­jām at­šķi­rī­bām starp tiem ir Python stingrā izteikumu un iz­teik­smes no­šķir­ša­na. Izteikumi ir soļi koda izpildē, bet iz­teik­smes tiek no­vēr­tē­tas kā vērtība.

Def sāk pa­zi­ņo­ju­mu, vai, precīzāk , salikto pa­zi­ņo­ju­mu, kas satur turpmākus pa­zi­ņo­ju­mus. def pa­zi­ņo­ju­mā var pa­rā­dī­ties tikai return pa­zi­ņo­jums. return pa­zi­ņo­jums atgriež vērtību, kad tiek izsaukta ar def definētā funkcija.

Atšķirībā no def izteikuma, lambda sāk izteikumu, kas nevar saturēt nekādus iz­tei­ku­mus. Lambda izteikums pieņem vienu vai vairākus ar­gu­men­tus un atgriež anonīmu funkciju. Kad tiek izsaukta lambda funkcija, tajā ie­tver­tais izteikums tiek izvērtēts ar no­do­ta­jiem ar­gu­men­tiem un atgriezts.

Kādi ir Python lambda izteikumu ie­ro­be­žo­ju­mi?

Python ir apzināti ie­ro­be­žo­jis lambda funkciju liet­de­rī­bu, jo parasti ir labāk nosaukt funkcijas. Tas liek prog­ram­mē­tā­jiem domāt par funkcijas nozīmi un skaidri nošķirt tās daļas.

Lambdas nevar saturēt ins­truk­ci­jas, atšķirībā no funkcijas ķermeņa, kas definēts ar at­slēg­vār­du def. Tāpēc lambda funkcijā nav iespējams izmantot if, for utt. Nav iespējams arī izraisīt izņēmumu, jo tam ne­pie­cie­ša­ma raise ins­truk­ci­ja.

Lambda funkcijas Python var saturēt vienu izteiksmi, kas tiek izvērtēta, kad tā tiek izsaukta. Lambda iz­teik­smes ietvaros nevar izmantot tipa ano­tā­ci­jas. Mūsdienās lielākajā daļā Python lambda funkciju lie­to­ša­nas gadījumu tiek iz­man­to­tas citas metodes, piemēram, izpratne.

Lambda funkciju dažādi lietojumi Python valodā

Lambda ir at­va­si­nā­tas no fun­kcio­nā­lās prog­ram­mē­ša­nas. Dažās valodās, piemēram, Ja­vaScript, anonīmas funkcijas tiek plaši iz­man­to­tas bez ne­pie­cie­ša­mī­bas pēc īpašas at­slēg­vār­da. Python valodā lambda iz­teik­smes tiek iz­man­to­tas, lai lokāli izveidotu nelielas funkcijas. Tur­pi­nā­ju­mā ap­ska­tī­sim to vis­no­de­rī­gā­kos pie­lie­to­ju­mus.

Kā aizpildīt augstākas kārtas funkcijas Python ar lambdas

Lambdas bieži tiek iz­man­to­tas ar augstākas kārtas funkcijām, piemēram, map(), filter() un reduce(). Iterējamo elementus var pārveidot bez cilpu iz­man­to­ša­nas, pa­tei­co­ties lambdas. Augstākas kārtas funkcijas ir funkcijas, kas kā pa­ra­met­rus izmanto funkcijas vai atgriež funkciju.

Funkcija map() kā pa­ra­met­rus pieņem funkciju un iterējamu objektu. Tā izpilda funkciju katram iterējama objekta elementam. Pa­mē­ģi­nā­sim ģenerēt kvad­rātskait­ļus. Mēs iz­man­to­jam funkciju map() un kā argumentu nododam lambda izteiksmi, kas ģenerē kvadrāta funkciju. Kvadrāta funkcija tiek piemērota katram saraksta elementam ar 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

Sākot ar Python 3.0, funkcijas map() un filter() atgriež iterējamu objektu, nevis sarakstu. list() izsaukums tiek izmantots assert iz­tei­ku­mos, lai izpakotu ite­rē­ja­mus objektus sarakstā.

Saraksta izpratne piedāvā modernāku pieeju iterējamo objektu apstrādei. Tā vietā, lai izmantotu map() un ģenerētu lambda funkciju, mēs varam aprakstīt operāciju tieši:

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

Funkciju filter() var izmantot, lai filtrētu ite­rē­ja­mas struk­tū­ras elementus. Mēs varam pa­pla­ši­nāt mūsu piemēru, lai ģenerētu tikai pāra kvad­rātskait­ļus:

# 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

Mēs parādām vēlamo pieeju, iz­man­to­jot saraksta izpratni, lai iegūtu to pašu rezultātu, ne­iz­man­to­jot lambdas un augstākas kārtas funkcijas. Izpratnes if daļa tiek izmantota, lai atlasītu pāra skaitļus no ģe­ne­rē­ta­jiem kvad­rātskait­ļiem:

# 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 nav iekļauta standarta bib­lio­tē­kā kopš Python 3.0 versijas. Šo funkciju var atrast functools modulī.

Kā īstenot galvenās funkcijas Python ar lambdas

Com­pre­hen­sions ir lielā mērā aiz­stā­ju­šas klasiskās augstākas kārtas funkcijas map() un filter() Python. Tomēr galvenās funkcijas var izmantot, lai parādītu lambda pilnīgo po­ten­ciā­lu.

Python sa­lī­dzi­nā­ša­nas funkcijas sorted(), min() un max() darbojas ar ite­rē­ja­miem objektiem. Katrs iterējama objekta elements tiek sa­lī­dzi­nāts, kad tiek izsaukta funkcija. Trīs funkcijas pieņem atslēgas funkciju kā ne­ob­li­gā­tu key parametru. Atslēgas funkcija tiek izsaukta katram elementam un atgriež atslēgas vērtību sa­lī­dzi­nā­ša­nas ope­rā­ci­jai.

Apsveriet šādu problēmu. Mums ir mape ar attēlu failiem, kuru nosaukumi ir saistīti ar Python sarakstu. Mēs vēlamies šo sarakstu sakārtot. Visi failu nosaukumi sākas ar img, kam seko skaitlis:

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

Ja iz­man­to­jam Python sorted() funkciju, tiek izmantota lek­si­kog­rā­fis­kā secība. Tā secīgus ciparus uzskata par at­se­viš­ķiem skaitļiem. Tādējādi skaitļi ['1', '2', '100'] tiek sakārtoti secībā ['1', '100', '2']. Rezultāts nav tāds, kādu gaidījām:

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

Mēs nododam lambda izteiksmi, kas rada atslēgas funkciju, lai no­dro­ši­nā­tu pareizu šķirošanu. Atslēgas funkcija izgūst faila nosaukuma ciparu daļu, ko sorted() izmanto kā atslēgu:

# 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

Galvenā funkcija tiek izmantota lokāli un tikai vienu reizi. Nav ne­pie­cie­šams definēt papildu nosaukumu tai. Lambdas ir pareizais veids, kā izveidot galvenās funkcijas. Ap­ska­tī­sim vēl divus piemērus.

Tāpat kā sorted(), arī iebūvētās Python funkcijas min() un max() pieņem fa­kul­ta­tī­vu atslēgas funkciju. Funkcijas atrod mazāko un lielāko elementu sarakstā vai citā iterējamā objektā. Mazākais vai lielākais elements ir de­fi­nī­ci­jas jautājums un to var norādīt, iz­man­to­jot atslēgas funkciju.

Ir skaidrs, ko nozīmē mazākais vai lielākais elements vienkāršu vērtību sarakstos, piemēram, skaitļu sarakstā. Šajā gadījumā mums nav ne­pie­cie­ša­ma īpaša atslēgas funkcija:

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

Ja netiek nodota neviena atslēgas funkcija, kā no­klu­sē­ju­ma funkcija tiek izmantota iden­ti­tā­tes funkcija f(x) = x. To var viegli definēt kā Python lambda ar lambda x: x.

Bet kas notiek, ja katrs iterējama elementa elements ietver vairākus datumus? Ie­do­mā­si­mies sarakstu ar vārdnīcām, kas attēlo cilvēkus ar viņu vārdiem un vecumu. Kāds ir kritērijs min() un max() gadījumā, lemjot, kurš ir mazākais un kurš lielākais elements? Šeit noderīga ir atslēgas funkcija.

Mums ir ne­pie­cie­ša­mi parauga dati, lai ilustrētu, kā darbojas galvenās funkcijas. Iz­vei­do­sim funkciju Person(), kas kalpos kā kons­truk­tors:

# 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

Mēs iz­vei­do­jam cilvēku sarakstu, iz­man­to­jot mūsu kons­truk­to­ra funkciju:

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

Mēs atrodam vecāko personu, iz­man­to­jot max() izsaukumu. Tas ģenerē atslēgas funkciju, iz­man­to­jot lambda izteiksmi, kas ņem personas diktu un izgūst no tā vecumu kā sa­lī­dzi­nā­ša­nas elementu:

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

Šī pieeja darbojas tieši tāpat arī min() funkcijā. Šajā gadījumā mēs definēsim galveno funkciju ārpus min() izsaukuma un atkal iz­man­to­sim lambda izteiksmi. Tas uzlabo lasāmību un ir liet­de­rī­gi, ja gal­ve­na­jai funkcijai ir vairāki vietējie lietojumi:

# 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

Kā izveidot slēgumus ar Python lambdas

Python lambdas tiek iz­man­to­tas arī, definējot slēgumus. Tās ir funkcijas, kuras izveido citas funkcijas un kuras glabā vērtību. Slēgumus var izmantot, lai izveidotu līdzīgu funkciju grupas. Parādīsim tipisku piemēru, kurā tiek iz­vei­do­tas potences funkcijas.

Potenču funkcijas pieņem argumentu un to ek­spo­nen­ciā­li aprēķina. Kvadrāta funkcija f(x) = x ^ 2 un kubiska funkcija f(x) = x ^ 3 ir labi zināmi piemēri. Jebkuras potences funkcijas var ģenerēt kā slēgumus, iz­man­to­jot kons­truk­to­ra funkciju. Mēs iz­man­to­sim lambda izteiksmi, kas nozīmē, ka mums nav jādefinē iekšējā nosaukta funkcija:

# 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

Kā izmantot ne­ka­vē­jo­ties izsaukto funkciju izteiksmi (IIFE) ar Python lambdas

IIFE, izrunā kā „iffy”, ir pazīstams modelis Ja­vaScript. Tas ietver anonīmas funkcijas de­fi­nē­ša­nu un tās tūlītēju izpildi.

Lambda var izmantot kā IIFE, lai gan tās nav īpaši noderīgas Python ie­ro­be­žo­ju­mu dēļ. Mums tikai jāievieto lambda izteiksme iekavās:

(lambda num: num * num)
python

Un vēl viena pāri iekavās, kas satur argumentu(-us):

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