Sådan bruges lambda-funktioner i Python
Lambda-funktioner har været en metode til funktionel programmering siden Python 1.0. I de senere år har andre teknikker imidlertid vundet større popularitet og i vid udstrækning erstattet lambdaer. Ikke desto mindre er der stadig nogle specialiserede anvendelser for lambdaer, som kyndige Python-programmører bør kende til.
Hvad er lambda-funktioner i Python?
I Python refererer lambda-funktionen til en anonym funktion. Python bruger nøgleordet lambda til at oprette en lambda-funktion. Et lambda-udtryk består af nøgleordet lambda efterfulgt af en liste over argumenter, et kolon og et enkelt udtryk. Udtrykket forsynes med argumenterne og evalueres, når lambda-funktionen kaldes:
lambda argument: expressionFunktioner er en grundlæggende sprogkonstruktion i næsten alle programmeringssprog, og de repræsenterer den mindste genanvendelige enhed af kode. Typisk defineres funktioner i Python med nøgleordet def. Vi viser dig kvadratfunktionen, der multiplicerer et tal med sig selv, som et eksempel:
# Define square function
def square(num):
return num * num
# Show that it works
assert square(9) == 81pythonNøgleordet def er en velkendt måde at definere funktioner på i Python, men sproget har også lambdas. Dette er anonyme funktioner, der definerer et udtryk med parametre. Lambdas kan bruges overalt, hvor en funktion forventes eller kan tildeles et navn. Du kan se lambda-udtrykket, der svarer til kvadratfunktionen, her:
# Create square function
squared = lambda num: num * num
# Show that it works
assert squared(9) == 81pythonHvad er forskellen mellem lambda og def?
Det kan virke underligt, at Python lader dig oprette funktioner med både lambda og def. Men Lambda er ikke en egen funktion, men blot en anden måde at oprette korte funktioner lokalt på. Alle funktioner, der oprettes med lambda, kan også oprettes med def. Det gælder dog ikke omvendt.
På det syntaktiske niveau er lambda og def begge nøgleord. En vigtig forskel mellem dem er Pythons strenge adskillelse af sætninger og udtryk. Sætninger er trin i udførelsen af kode, mens udtryk evalueres til en værdi.
Def indleder en sætning, eller mere specifikt en sammensat sætning, som indeholder yderligere sætninger. Der må kun forekomme return sætninger inden for en def sætning. En return sætning returnerer en værdi, når den funktion, der er defineret med def, kaldes.
I modsætning til def starterlambda et udtryk, der ikke kan indeholde nogen sætninger. Lambda-udtrykket tager et eller flere argumenter og returnerer en anonym funktion. Når lambda-funktionen kaldes, evalueres det udtryk, den indeholder, med de overførte argumenter, og det returneres.
Hvad er begrænsningerne ved Pythons lambda-udtryk?
Python har bevidst begrænset nytten af lambda-funktioner, da det normalt er bedre at navngive funktioner. Dette tvinger programmører til at tænke over funktionens betydning og skelne klart mellem de forskellige dele.
Lambdaer kan ikke indeholde instruktioner, i modsætning til kroppen af en funktion defineret med nøgleordet def. Det er derfor ikke muligt at bruge if, for osv. i en lambda-funktion. Det er heller ikke muligt at udløse en undtagelse, da dette kræver en raise.
Lambda-funktioner i Python kan indeholde et enkelt udtryk, der evalueres, når det kaldes. Typeannotationer kan ikke bruges i lambda-udtrykket. I dag bruger de fleste anvendelsestilfælde af lambda-funktioner i Python andre teknikker, såsom comprehensions.
Forskellige anvendelser af lambda-funktioner i Python
Lambdaer stammer fra funktionel programmering. I nogle sprog, såsom JavaScript, bruges anonyme funktioner i vid udstrækning uden behov for et særligt nøgleord. I Python bruges lambda-udtryk til at oprette små funktioner lokalt. Vi gennemgår deres mest nyttige anvendelser nedenfor.
Sådan udfyldes højere ordensfunktioner i Python med lambdas
Lambdaer bruges ofte sammen med højere ordensfunktioner som map(), filter() og reduce(). Elementerne i en iterabel kan transformeres uden brug af sløjfer takket være lambdaer. Højere ordensfunktioner er funktioner, der tager funktioner som parametre eller returnerer en funktion.
Funktionen map() tager en funktion og en iterabel som parametre. Den udfører funktionen for hvert element i den iterable. Lad os prøve at generere kvadratnumre. Vi bruger funktionen map() og sender et lambda-udtryk som argument, hvilket genererer kvadratfunktionen. Kvadratfunktionen anvendes på hvert element i listen med 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]pythonFra og med Python 3.0 returnerer funktionerne map() og filter() en iterabel i stedet for en liste. Et list() -kald bruges i assert -sætningerne til at udpakke iterabler til en liste.
List comprehensions tilbyder en mere moderne tilgang til behandling af iterables. I stedet for at ty til map() og generere en lambda-funktion, kan vi beskrive operationen direkte:
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]pythonFunktionen filter() kan bruges til at filtrere elementerne i en iterabel. Vi kan udvide vores eksempel til kun at generere lige kvadratnumre:
# 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]pythonVi viser den foretrukne tilgang, hvor man bruger listeforståelse til at generere det samme resultat uden at bruge lambdas og højere ordensfunktioner. Den if del af forståelsen bruges til at filtrere de lige tal fra de genererede kvadratnumre:
# 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]pythonPythons reduce() -funktion er ikke blevet inkluderet i standardbiblioteket siden Python 3.0. Denne funktion kan findes i functools -modulet.
Sådan implementeres nøglefunktioner i Python med lambdas
Comprehensions har i vid udstrækning erstattet de klassiske højere ordensfunktioner map() og filter() i Python. Nøglefunktioner kan dog bruges til at demonstrere lambdas fulde styrker.
Python-sammenligningsfunktionerne sorted(), min() og max() fungerer på iterable. Hvert element i iterable underkastes en sammenligning, når det kaldes. De tre funktioner tager en nøglefunktion som en valgfri key parameter. Nøglefunktionen kaldes for hvert element og returnerer en nøgleværdi til sammenligningsoperationen.
Lad os se på følgende problem. Vi har en mappe med billedfiler, hvor navnene er knyttet til en Python-liste. Vi vil sortere listen. Alle filnavne starter med img efterfulgt af et tal:
# List of image file names
images = ['img1', 'img2', 'img30', 'img3', 'img22', 'img100']pythonHvis vi bruger Pythons sorted(), anvendes den leksikografiske rækkefølge. Her behandles på hinanden følgende cifre som enkeltcifre. Derfor placeres tallet ['1', '2', '100'] i rækkefølgen ['1', '100', '2']. Resultatet er ikke som forventet:
# Sort using lexicographic order
sorted_image = sorted(images)
# Show that it works
assert sorted_image == ['img1', 'img100', 'img2', 'img22', 'img3', 'img30']pythonVi sender et lambda, der producerer en nøglefunktion for at sikre, at sorteringen er korrekt. Nøglefunktionen udtrækker den numeriske del af et filnavn, som bruges som nøgle af 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']pythonNøglefunktionen bruges lokalt og kun én gang. Det er ikke nødvendigt at definere en ekstra navngiven funktion til den. Lambdas er den korrekte måde at oprette nøglefunktioner på. Lad os se på to flere eksempler.
Ligesom sorted() tager de indbyggede Python-funktioner min() og max() en valgfri nøglefunktion. Funktionerne finder det mindste og største element i en liste eller anden iterabel. Det mindste eller største element er et spørgsmål om definition og kan specificeres ved hjælp af nøglefunktionen.
Det er klart, hvad der menes med det mindste eller største element for lister med enkle værdier, såsom en liste med tal. I dette tilfælde har vi ikke brug for en særlig nøglefunktion:
nums = [42, 69, 51, 13]
assert min(nums) == 13
assert max(nums) == 69pythonHvis der ikke overføres nogen nøglefunktion, bruges identitetsfunktionen f(x) = x som standard. Dette kan nemt defineres som en Python-lambda med lambda x: x.
Men hvad nu hvis hvert element i en iterabel indeholder flere datoer? Lad os forestille os en liste med ordbøger, der repræsenterer personer med deres navne og alder. Hvad er kriteriet for min() og max(), når man skal beslutte, hvilket element der er det mindste og det største? Det er her, en nøglefunktion er nyttig.
Vi har brug for eksempeldata for at illustrere, hvordan nøglefunktioner fungerer. Lad os oprette en funktion Person(), der fungerer som en konstruktør:
# 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}pythonVi opretter en liste over personer ved hjælp af vores konstruktorfunktion:
# Create list of people
people = [person('Jim', 42), person('Jack', 51), person('John', 69)]pythonVi finder den ældste person ved hjælp af max(). Dette genererer en nøglefunktion ved hjælp af lambda-udtrykket, som tager en person-dict og udtrækker alderen fra den som et sammenligningselement:
# Find the oldest person
oldest = max(people, key=lambda person: person['age'])
# Check that it works
assert oldest == Person('John', 69)pythonTilgangen fungerer nøjagtigt på samme måde for funktionen min(). I dette tilfælde definerer vi nøglefunktionen uden for min() kaldet og bruger igen et lambda-udtryk. Dette forbedrer læsbarheden og er værdifuldt, hvis nøglefunktionen har flere lokale anvendelser:
# 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)pythonSådan oprettes lukninger med Python-lambdaer
Python-lambdaer bruges også til at definere lukninger. Det er funktioner, der oprettes af andre funktioner og gemmer en værdi. Lukninger kan bruges til at oprette familier af lignende funktioner. Vi viser et almindeligt eksempel, hvor der oprettes potensfunktioner.
Potensfunktioner tager et argument og eksponerer det. Kvadratfunktionen f(x) = x ^ 2 og kubikfunktionen f(x) = x ^ 3 er velkendte eksempler. Vilkårlige potensfunktioner kan genereres som lukninger ved hjælp af en konstruktorfunktion. Vi bruger et lambda-udtryk, hvilket betyder, at vi ikke behøver at definere en indre navngivet funktion:
# 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) == 1000pythonSådan bruges IIFE (Immediately Invoked Function Expression) med Python-lambdaer
IIFE, udtalt ‘iffy’, er et kendt mønster i JavaScript. Det indebærer at definere en anonym funktion og udføre den med det samme.
Lambdaer kan bruges som IIFE’er, selvom de ikke er særlig nyttige på grund af begrænsninger i Python. Vi behøver kun at sætte parenteser omkring lambda-udtrykket:
(lambda num: num * num)pythonOg endnu et par parenteser, der indeholder argumentet/argumenterne:
assert (lambda num: num * num)(3) == 9python