Lambda-funksjoner har vært en metode for funksjonell programmering siden Python 1.0. De siste årene har imidlertid andre teknikker blitt mer populære og i stor grad erstattet lambdaer. Likevel finnes det fortsatt noen spesielle bruksområder for lambdaer som dyktige Python-programmerere bør kjenne til.

Hva er lambda-funksjoner i Python?

I Python refererer lambda-funksjon til en anonym funksjon. Python bruker nøkkelordet lambda for å opprette en lambda-funksjon. Et lambda-uttrykk består av nøkkelordet lambda etterfulgt av en liste med argumenter, et kolon og et enkelt uttrykk. Uttrykket får argumentene og evalueres når lambda-funksjonen kalles:

lambda argument: expression

Funksjoner er en grunnleggende språkkonstruksjon i nesten alle programmeringsspråk, og de representerer den minste gjenbrukbare kodenheten. Funksjoner i Python defineres vanligvis med nøkkelordet def. Vi viser deg kvadratfunksjonen som multipliserer et tall med seg selv som et eksempel:

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

Nøkkelordet def er en velkjent måte å definere funksjoner på i Python, men språket har også lambdas. Dette er anonyme funksjoner som definerer et uttrykk med parametere. Lambdas kan brukes hvor som helst der en funksjon forventes eller kan tilordnes et navn. Her kan du se lambda-uttrykket som tilsvarer kvadratfunksjonen:

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

Hva er forskjellen mellom lambda og def?

Det kan virke rart at Python lar deg lage funksjoner med både lambda og def. Men Lambda er ikke en egen funksjon, snarere bare en annen måte å lage korte funksjoner lokalt på. Alle funksjoner som er laget med lambda, kan også lages med def. Men det er ikke motsatt.

På syntaktisk nivå er både lambda og def nøkkelord. En viktig forskjell mellom dem er Pythons strenge skille mellom setninger og uttrykk. Setninger er trinn i utførelsen av kode, mens uttrykk evalueres til en verdi.

Def starter en setning, eller mer spesifikt en sammensatt setning, som inneholder flere setninger. Bare return setninger kan vises i en def setning. En return setning returnerer en verdi når funksjonen definert med def kalles.

I motsetning til def starterlambda et uttrykk som ikke kan inneholde noen utsagn. Lambda-uttrykket tar ett eller flere argumenter og returnerer en anonym funksjon. Når lambda-funksjonen kalles, blir uttrykket i den evaluert med de overførte argumentene, og det returneres.

Hva er begrensningene ved Pythons lambda-uttrykk?

Python har bevisst begrenset nytten av lambda-funksjoner, da det vanligvis er bedre å gi funksjoner navn. Dette tvinger programmerere til å tenke gjennom funksjonens betydning og skille klart mellom de ulike delene.

Lambdaer kan ikke inneholde instruksjoner, i motsetning til kroppen av en funksjon definert med nøkkelordet def. Det er derfor ikke mulig å bruke if, for osv. i en lambdafunksjon. Det er heller ikke mulig å utløse en unntakssituasjon, da dette krever en raise.

Lambda-funksjoner i Python kan inneholde et enkelt uttrykk som evalueres når det kalles. Typeanmerkninger kan ikke brukes i lambda-uttrykket. I dag bruker de fleste bruksområder for lambda-funksjoner i Python andre teknikker, for eksempel forståelser.

Ulike bruksområder for lambda-funksjoner i Python

Lambdaer stammer fra funksjonell programmering. I noen språk, for eksempel JavaScript, brukes anonyme funksjoner mye uten at det er behov for et spesielt nøkkelord. I Python brukes lambda-uttrykk til å lage små funksjoner lokalt. Vi skal se på de mest nyttige anvendelsene nedenfor.

Hvordan fylle ut funksjoner av høyere orden i Python med lambdas

Lambdaer brukes ofte med funksjoner av høyere orden, som map(), filter() og reduce(). Elementene i en iterabel kan transformeres uten å bruke løkker takket være lambdaer. Funksjoner av høyere orden er funksjoner som tar funksjoner som parametere eller returnerer en funksjon.

Funksjonen map() tar en funksjon og en iterabel som parametere. Den utfører funksjonen for hvert element i den iterable. La oss prøve å generere kvadratiske tall. Vi bruker funksjonen map() og sender et lambda-uttrykk som argument, som genererer kvadratfunksjonen. Kvadratfunksjonen brukes 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]
python
Note

Fra og med Python 3.0 returnerer funksjonene map() og filter() en iterabel i stedet for en liste. Et list() all brukes inne i assert setningene for å pakke ut iterabler til en liste.

Listeforståelser tilbyr en mer moderne tilnærming til behandling av iterable. I stedet for å ty til map() og generere en lambda-funksjon, kan vi beskrive operasjonen 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]
python

Funksjonen filter() kan brukes til å filtrere elementene i en iterabel. Vi kan utvide eksemplet vårt til å generere bare partall:

# 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

Vi viser den foretrukne tilnærmingen med å bruke listeforståelse for å generere det samme resultatet uten å bruke lambdas og funksjoner av høyere orden. Den if delen av forståelsen brukes til å filtrere ut de partallene fra de genererte kvadratnumrene:

# 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

Pythons reduce() -funksjon har ikke vært inkludert i standardbiblioteket siden Python 3.0. Denne funksjonen finnes i functools -modulen.

Hvordan implementere nøkkelfunksjoner i Python med lambdas

Comprehensions har i stor grad erstattet de klassiske høyere ordensfunksjonene map() og filter() i Python. Imidlertid kan nøkkelfunksjoner brukes til å demonstrere lambdas fulle styrke.

Python-sammenligningsfunksjonene sorted(), min() og max() opererer på iterable. Hvert element i iterable blir sammenlignet når det kalles. De tre funksjonene tar en nøkkelfunksjon som en valgfri key parameter. Nøkkelfunksjonen kalles for hvert element og returnerer en nøkkelverdi for sammenligningsoperasjonen.

La oss se på følgende problem. Vi har en mappe med bildefiler hvor navnene er tilordnet en Python-liste. Vi ønsker å sortere listen. Alle filnavnene starter med img, etterfulgt av et tall:

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

Hvis vi bruker Python-funksjonen sorted(), brukes leksikografisk rekkefølge. Dette behandler påfølgende sifre som enkeltstående tall. Dermed blir tallene ['1', '2', '100'] plassert i rekkefølgen ['1', '100', '2']. Resultatet blir ikke som forventet:

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

Vi sender et lambda som produserer en nøkkelfunksjon for å sikre at sorteringen er korrekt. Nøkkelfunksjonen trekker ut den numeriske delen av et filnavn, som brukes som nøkkel av 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

Nøkkelfunksjonen brukes lokalt og bare én gang. Det er ikke nødvendig å definere en ekstra navngitt funksjon for den. Lambdas er den riktige måten å lage nøkkelfunksjoner på. La oss se på to eksempler til.

I likhet med sorted() har de innebygde Python-funksjonene min() og max() en valgfri nøkkelfunksjon. Funksjonene finner det minste og største elementet i en liste eller annen iterabel. Det minste eller største elementet er et spørsmål om definisjon og kan spesifiseres ved hjelp av nøkkelfunksjonen.

Det er klart hva som menes med minste eller største element for lister med enkle verdier, for eksempel en liste med tall. I dette tilfellet trenger vi ikke en spesiell nøkkelfunksjon:

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

Hvis ingen nøkkelfunksjon overføres, brukes identitetsfunksjonen f(x) = x som standard. Dette kan enkelt defineres som en Python-lambda med lambda x: x.

Men hva om hvert element i en iterabel inneholder flere datoer? La oss forestille oss en liste med ordbøker som representerer personer med navn og alder. Hva er kriteriene for min() og max() når man skal bestemme hvilket som er det minste og største elementet? Det er her en nøkkelfunksjon kommer til nytte.

Vi trenger eksempeldata for å illustrere hvordan nøkkelfunksjoner fungerer. La oss lage en funksjon Person() som 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}
python

Vi oppretter en liste over personer ved hjelp av vår konstruktorfunksjon:

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

Vi finner den eldste personen ved hjelp av max(). Dette genererer en nøkkelfunksjon ved hjelp av lambda-uttrykket, som tar en person-dict og trekker ut 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)
python

Tilnærmingen fungerer nøyaktig på samme måte for funksjonen min(). I dette tilfellet definerer vi nøkkelfunksjonen utenfor min() kallet og bruker igjen et lambda-uttrykk. Dette forbedrer lesbarheten og er verdt å gjøre hvis nøkkelfunksjonen har flere lokale bruksområder:

# 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

Hvordan lage lukninger med Python-lambdaer

Python-lambdaer brukes også når man definerer lukninger. Dette er funksjoner som opprettes av andre funksjoner og lagrer en verdi. Lukninger kan brukes til å opprette familier av lignende funksjoner. Vi viser et vanlig eksempel der potensfunksjoner opprettes.

Potensfunksjoner tar et argument og eksponerer det. Kvadratfunksjonen f(x) = x ^ 2 og kubikkfunksjonen f(x) = x ^ 3 er velkjente eksempler. Vilkårlige potensfunksjoner kan genereres som lukninger ved hjelp av en konstruktorfunksjon. Vi bruker et lambda-uttrykk, noe som betyr at vi ikke trenger å definere en indre navngitt funksjon:

# 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

Hvordan bruke umiddelbart påkalt funksjonsuttrykk (IIFE) med Python-lambdaer

IIFE, uttalt «iffy», er et kjent mønster i JavaScript. Det innebærer å definere en anonym funksjon og utføre den umiddelbart.

Lambdaer kan brukes som IIFE-er, selv om de ikke er særlig nyttige på grunn av begrensninger i Python. Vi trenger bare å sette parenteser rundt lambda-uttrykket:

(lambda num: num * num)
python

Og et annet par parenteser som inneholder argumentet/argumentene:

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