Kako uporabljati lambda funkcije v Pythonu
Lambda funkcije so bile metoda za funkcionalno programiranje že od Python 1.0. Vendar pa so v zadnjih letih druge tehnike pridobile večjo priljubljenost in v veliki meri nadomestile lambda funkcije. Kljub temu pa obstajajo še vedno nekatere specializirane uporabe lambda funkcij, ki jih morajo poznati izkušeni Python programerji.
Kaj so lambda funkcije v Pythonu?
V Pythonu se lambda funkcija nanaša na anonimno funkcijo. Python uporablja ključno besedo lambda za ustvarjanje lambda funkcije. Lambda izraz je sestavljen iz ključne besede lambda, ki ji sledi seznam argumentov, dvopičje in en izraz. Izraz je opremljen z argumenti in se izračuna, ko se pokliče lambda funkcija:
lambda argument: expressionFunkcije so temeljna jezikovna konstrukcija v skoraj vseh programskih jezikih in predstavljajo najmanjšo ponovno uporabno enoto kode. Običajno so funkcije v Pythonu definirane s ključno besedo def. Kot primer vam bomo pokazali kvadratno funkcijo, ki pomnoži število s samim sabo:
# Define square function
def square(num):
return num * num
# Show that it works
assert square(9) == 81pythonKljučna beseda def je znan način za definiranje funkcij v Pythonu, vendar jezik pozna tudi lambda izraze. To so anonimne funkcije, ki definirajo izraz s parametri. Lambda izrazi se lahko uporabljajo povsod, kjer se pričakuje funkcija ali kjer se lahko dodelijo imenu. Tukaj si lahko ogledate lambda izraz, ki je enakovreden kvadratni funkciji:
# Create square function
squared = lambda num: num * num
# Show that it works
assert squared(9) == 81pythonKakšna je razlika med lambda in def?
Morda se zdi čudno, da Python omogoča ustvarjanje funkcij tako z lambda kot z def. Vendar Lambda ni njegova lastna funkcija, ampak le še en način za lokalno ustvarjanje kratkih funkcij. Vsaka funkcija, ustvarjena z lambda, se lahko ustvari tudi z def. Vendar pa to ne velja v obratni smeri.
Na sintaktični ravni sta lambda in def ključni besedi. Ena ključna razlika med njima je stroga ločitev izjav in izrazov v Pythonu. Izjave so koraki pri izvajanju kode, medtem ko se izrazi ovrednotijo v vrednost.
Def začne izjavo, natančneje sestavljeno izjavo, ki vsebuje nadaljnje izjave. V izjavi def se lahko pojavi samo return izjava. Izjava return vrne vrednost, ko se pokliče funkcija, definirana z def.
Za razliko od izjave def, lambda začne izraz, ki ne more vsebovati nobenih izjav. Lambda izraz sprejme enega ali več argumentov in vrne anonimno funkcijo. Ko se lambda funkcija pokliče, se izraz, ki je v njej, ovrednoti s prenesenimi argumenti in se vrne.
Kakšne so omejitve lambda izrazov v Pythonu?
Python je namerno omejil uporabnost lambda funkcij, saj je običajno bolje poimenovati funkcije. To programerje prisili, da razmislijo o pomenu funkcije in jasno razlikujejo med posameznimi deli.
Lambda izrazi ne morejo vsebovati navodil, za razliko od telesa funkcije, definirane s ključno besedo def. Zato v lambda funkciji ni mogoče uporabiti if, for itd. Prav tako ni mogoče sprožiti izjeme, saj je za to potrebna izjava raise.
Lambda funkcije v Pythonu lahko vsebujejo en sam izraz, ki se izračuna ob klicu. Tipovne opombe se ne morejo uporabljati znotraj lambda izraza. Danes večina primerov uporabe lambda funkcij v Pythonu uporablja druge tehnike, kot so razumevanja.
Različne uporabe lambda funkcij v Pythonu
Lambda izhaja iz funkcionalnega programiranja. V nekaterih jezikih, kot je JavaScript, se anonimne funkcije pogosto uporabljajo brez potrebe po posebni ključni besedi. V Pythonu se lambda izrazi uporabljajo za lokalno ustvarjanje majhnih funkcij. V nadaljevanju bomo pregledali njihove najbolj uporabne aplikacije.
Kako v Pythonu napolniti funkcije višjega reda z lambda izrazi
Lambde se pogosto uporabljajo z višjimi funkcijami, kot so map(), filter() in reduce(). Elementi iterabilnega niza se lahko preoblikujejo brez uporabe zank, zahvaljujoč lambdam. Višje funkcije so funkcije, ki sprejemajo funkcije kot parametre ali vrnejo funkcijo.
Funkcija map() sprejme funkcijo in iterabilno kot parametre. Izvede funkcijo za vsak element iterabilnega. Poskusimo ustvariti kvadratne številke. Uporabimo funkcijo map() in kot argument prenesemo lambda izraz, ki ustvari kvadratno funkcijo. Kvadratna funkcija se uporabi za vsak element seznama s 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]pythonOd Python 3.0 naprej funkcije map() in filter() vrnejo iterabilno namesto seznama. Klic list() se uporablja znotraj izjav assert za razpakiranje iterabilnih v seznam.
Seznami razumevanj ponujajo sodobnejši pristop za obdelavo iterabilnih elementov. Namesto da se zatečemo k map() in ustvarimo lambda funkcijo, lahko operacijo opišemo neposredno:
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]pythonFunkcijo filter() lahko uporabimo za filtriranje elementov iterabilnega niza. Naš primer lahko razširimo tako, da generiramo samo sode kvadratne številke:
# 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]pythonPrikazujemo prednostni pristop uporabe razumevanja seznama za ustvarjanje enakega rezultata brez uporabe lambd in funkcij višjega reda. Del razumevanja if se uporablja za filtriranje sodeštev iz ustvarjenih kvadratnih števil:
# 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]pythonFunkcija Python reduce() ni bila vključena v standardno knjižnico od Python 3.0. To funkcijo lahko najdete v modulu functools.
Kako implementirati ključne funkcije v Pythonu z lambdami
Razumevanja so v veliki meri nadomestila klasične funkcije višjega reda map() in filter() v Pythonu. Vendar pa se lahko ključne funkcije uporabijo za prikazovanje vseh prednosti lambd.
Pythonove primerjalne funkcije sorted(), min() in max() delujejo na iterabilnih objektih. Vsak element iterabilnega objekta je ob klicu predmet primerjave. Tri funkcije sprejemajo ključno funkcijo kot neobvezni parameter key. Ključna funkcija se pokliče za vsak element in vrne ključno vrednost za primerjalno operacijo.
Razmislimo o naslednjem problemu. Imamo mapo s slikovnimi datotekami, katerih imena so dodeljena seznamu v Pythonu. Seznam želimo razvrstiti. Vsa imena datotek se začnejo s img, ki ji sledi številka:
# List of image file names
images = ['img1', 'img2', 'img30', 'img3', 'img22', 'img100']pythonČe uporabimo funkcijo sorted() v Pythonu, se uporabi leksikografski red. Ta zaporedne številke obravnava kot eno samo število. Tako se številke ['1', '2', '100'] uvrstijo v red ['1', '100', '2']. Rezultat ni tak, kot smo pričakovali:
# Sort using lexicographic order
sorted_image = sorted(images)
# Show that it works
assert sorted_image == ['img1', 'img100', 'img2', 'img22', 'img3', 'img30']pythonPrehodimo izraz lambda, ki ustvari ključno funkcijo, da zagotovimo pravilno razvrščanje. Ključna funkcija izvleče številčni del imena datoteke, ki se uporabi kot ključ v 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']pythonKljučna funkcija se uporablja lokalno in samo enkrat. Ni potrebno, da zanjo opredelite dodatno imenovano funkcijo. Lambda izrazi so pravi način za ustvarjanje ključnih funkcij. Poglejmo si še dva primera.
Podobno kot sorted(), vgrajeni Pythonovi funkciji min() in max() sprejemata neobvezno ključno funkcijo. Funkciji poiščeta najmanjši in največji element v seznamu ali drugem iterabilnem objektu. Najmanjši ali največji element je stvar definicije in ga je mogoče določiti s ključno funkcijo.
Jasno je, kaj pomeni najmanjši ali največji element za sezname preprostih vrednosti, kot je seznam številk. V tem primeru ne potrebujemo posebne ključne funkcije:
nums = [42, 69, 51, 13]
assert min(nums) == 13
assert max(nums) == 69pythonČe ni prenesena nobena ključna funkcija, se kot privzeta uporabi identiteta funkcija f(x) = x. To se lahko enostavno definira kot Python lambda z lambda x: x.
Kaj pa, če vsak element iterabilnega niza vsebuje več datumov? Predstavljajmo si seznam slovarjev, ki predstavljajo ljudi z njihovimi imeni in starostmi. Kakšno je merilo za min() in max() pri odločanju, kateri je najmanjši in kateri največji element? Tukaj pride v poštev ključna funkcija.
Potrebujemo vzorčne podatke, da ponazorimo delovanje ključnih funkcij. Ustvarimo funkcijo Person(), ki služi kot konstruktor:
# 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}pythonSeznam oseb ustvarimo s pomočjo naše konstruktorske funkcije:
# Create list of people
people = [person('Jim', 42), person('Jack', 51), person('John', 69)]pythonNajdemo najstarejšo osebo z uporabo klica max(). To ustvari ključno funkcijo z uporabo lambda izraza, ki vzame slovar oseb in iz njega izvleče starost kot primerjalni element:
# Find the oldest person
oldest = max(people, key=lambda person: person['age'])
# Check that it works
assert oldest == Person('John', 69)pythonPristop deluje popolnoma enako za funkcijo min(). V tem primeru bomo ključno funkcijo definirali zunaj klica min() in ponovno uporabili lambda izraz. To izboljša berljivost in je koristno, če ima ključna funkcija več lokalnih uporab:
# 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)pythonKako ustvariti zapiranja s Pythonovimi lambdami
Pythonove lambda funkcije se uporabljajo tudi pri definiranju zapiranj. To so funkcije, ki jih ustvarijo druge funkcije in shranjujejo vrednost. Zapiranja se lahko uporabijo za ustvarjanje družin podobnih funkcij. Pokazali bomo pogost primer, kjer se ustvarjajo potenčne funkcije.
Funkcije potence sprejmejo argument in ga eksponentirajo. Funkcija kvadrata f(x) = x ^ 2 in funkcija kubika f(x) = x ^ 3 sta dobro znana primera. Poljubne funkcije potence lahko ustvarimo kot zaprtje s pomočjo konstruktorske funkcije. Uporabili bomo lambda izraz, kar pomeni, da nam ni treba definirati notranje imenovane funkcije:
# 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) == 1000pythonKako uporabljati takojšnjo izraženo funkcijo (IIFE) z Pythonovimi lambdami
IIFE, izgovorjeno kot „iffy“, je znan vzorec v JavaScriptu. Vključuje definiranje anonimne funkcije in njeno takojšnjo izvedbo.
Lambde se lahko uporabljajo kot IIFE, čeprav niso zelo uporabne zaradi omejitev v Pythonu. Lambda izraz moramo samo obdati z oklepaji:
(lambda num: num * num)pythonIn še en par oklepajev, ki vsebujejo argument(e):
assert (lambda num: num * num)(3) == 9python