Lambda-funktioiden käyttö Pythonissa
Lambda-funktiot ovat olleet funktionaalisen ohjelmoinnin menetelmä Python 1.0 :sta lähtien. Viime vuosina muut tekniikat ovat kuitenkin saavuttaneet suuremman suosion ja korvanneet lambdat suurelta osin. Siitä huolimatta lambdoilla on edelleen joitakin erikoistuneita käyttötarkoituksia, jotka taitavien Python-ohjelmoijien tulisi tuntea.
Mitä ovat lambda-funktiot Pythonissa?
Pythonissa lambda-funktio viittaa nimettömään funktioon. Python käyttää avainsanaa lambda lambda-funktion luomiseen. Lambda-lauseke koostuu avainsanasta lambda, jota seuraa argumenttien luettelo, kaksoispiste ja yksittäinen lauseke. Lauseke annetaan argumenteilla ja arvioidaan, kun lambda-funktio kutsutaan:
lambda argument: expressionFunktiot ovat lähes jokaisen ohjelmointikielen perusrakenteita, ja ne edustavat pienintä uudelleenkäytettävää koodiyksikköä. Tyypillisesti Pythonin funktiot määritellään def. Esitämme esimerkkinä neliöfunktion, joka kertoo luvun itsellään:
# Define square function
def square(num):
return num * num
# Show that it works
assert square(9) == 81pythondef on tunnettu tapa määritellä funktioita Pythonissa, mutta kielessä on myös lambda-funktiot. Nämä ovat nimettömiä funktioita, jotka määrittelevät lausekkeen parametreilla. Lambda-funktioita voidaan käyttää missä tahansa, missä funktiota odotetaan tai voidaan määrittää nimelle. Voit nähdä neliöfunktiota vastaavan lambda-lausekkeen tässä:
# Create square function
squared = lambda num: num * num
# Show that it works
assert squared(9) == 81pythonMitä eroa on lambda- ja def-sanoilla?
Saattaa tuntua oudolta, että Pythonissa voi luoda funktioita sekä lambda että def. Lambda ei kuitenkaan ole oma ominaisuus, vaan vain toinen tapa luoda lyhyitä funktioita paikallisesti. Jokainen lambda lla luotu funktio voidaan luoda myös def. Päinvastoin tämä ei kuitenkaan päde.
Syntaktisella tasolla lambda ja def ovat molemmat avainsanoja. Yksi keskeinen ero niiden välillä on Pythonin tiukka lausekkeiden ja lausumien erottelu. Lausekkeet ovat koodin suorittamisen vaiheita, kun taas lausumat arvioidaan arvoksi.
Def aloittaa lauseen, tarkemmin sanottuna yhdistetyn lauseen, joka sisältää muita lauseita. def voi esiintyä vain return lausetta. return palauttaa arvon, kun def llä määritelty funktio kutsutaan.
Toisin kuin def, lambda aloittaa lausekkeen, joka ei voi sisältää lauseita. Lambda-lauseke ottaa yhden tai useamman argumentin ja palauttaa nimettömän funktion. Kun lambda-funktio kutsutaan, sen sisältämä lauseke arvioidaan annetuilla argumenteilla ja palautetaan.
Mitkä ovat Pythonin lambda-lausekkeiden rajoitukset?
Python on tarkoituksella rajoittanut lambda-funktioiden käyttökelpoisuutta, koska yleensä on parempi nimetä funktiot. Tämä pakottaa ohjelmoijat miettimään funktion merkitystä ja erottamaan osat selkeästi toisistaan.
Lambdat eivät voi sisältää ohjeita, toisin kuin def määritellyn funktion runko. Siksi lambda-funktiossa ei ole mahdollista käyttää if, for jne. Ei ole myöskään mahdollista laukaista poikkeusta, koska se edellyttää raise.
Pythonin lambda-funktiot voivat sisältää yhden lausekkeen, joka arvioidaan kutsuttaessa. Tyyppimerkintöjä ei voi käyttää lambda-lausekkeessa. Nykyään useimmissa Pythonin lambda-funktioiden käyttötapauksissa käytetään muita tekniikoita, kuten comprehensions.
Lambda-funktioiden eri käyttötarkoitukset Pythonissa
Lambdat ovat peräisin funktionaalisesta ohjelmoinnista. Joissakin kielissä, kuten JavaScriptissä, nimettömiä funktioita käytetään laajalti ilman erityistä avainsanaa. Pythonissa lambda-lausekkeita käytetään pienten funktioiden luomiseen paikallisesti. Seuraavassa käymme läpi niiden hyödyllisimmät sovellukset.
Kuinka täyttää korkeamman asteen funktiot Pythonissa lambdoilla
Lambdoja käytetään usein korkeamman asteen funktioissa, kuten map(), filter() ja reduce(). Iteroitavan elementit voidaan muuntaa ilman silmukoita lambdojen ansiosta. Korkeamman asteen funktiot ovat funktioita, jotka ottavat parametreiksi funktioita tai palauttavat funktion.
map() ottaa parametreina funktion ja iterattavan. Se suorittaa funktion jokaiselle iterattavan elementille. Kokeillaanpa generoida neliölukuja. Käytämme map() ja välitämme argumenttina lambda-lausekkeen, joka generoi neliöfunktion. Neliöfunktio sovelletaan jokaiselle listan elementille map()lla:
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]pythonPython 3.0:sta alkaen funktiot map() ja filter() palauttavat iterable-tyyppisen arvon listan sijaan. list() kutsu käytetään assert -lauseiden sisällä iterable-tyyppisten arvojen purkamiseen listaksi.
List comprehension tarjoaa modernimman lähestymistavan iterable-tyyppisten tietojen käsittelyyn. Sen sijaan, että turvautuisimme map() een ja luomisimme lambda-funktion, voimme kuvata operaation suoraan:
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]pythonfilter() voidaan käyttää suodattamaan iterattavan elementtejä. Voimme laajentaa esimerkkiämme tuottamaan vain parillisia neliölukuja:
# 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]pythonEsitämme suositellun lähestymistavan, jossa käytetään listan ymmärtämistä saman tuloksen tuottamiseen ilman lambda-funktioita ja korkeamman asteen funktioita. Ymmärtämisen osaa if käytetään suodattamaan parilliset luvut tuotetuista neliöluvuista:
# 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]pythonPythonin reduce() -funktiota ei ole sisällytetty vakiokirjastoon Python 3.0:n jälkeen. Tämä funktio löytyy functools -moduulista.
Kuinka toteuttaa keskeisiä toimintoja Pythonissa lambdoilla
Comprehensions ovat suurelta osin korvanneet klassiset korkeamman asteen funktiot map() ja filter() Pythonissa. Kuitenkin avainfunktioita voidaan käyttää lambda-funktioiden kaikkien vahvuuksien esittelemiseen.
Pythonin vertailufunktiot sorted(), min() ja max() toimivat iterable-tyyppisillä kohteilla. Jokainen iterable-tyyppisen kohteen elementti verrataan, kun funktio kutsutaan. Nämä kolme funktiota ottavat vastaan avainfunktion valinnaisena parametrina key. Avainfunktio kutsutaan jokaiselle elementille ja palauttaa avainarvon vertailua varten.
Tarkastellaan seuraavaa ongelmaa. Meillä on kansio, jossa on kuvatiedostoja, joiden nimet on liitetty Python-listaan. Haluamme lajitella luettelon. Kaikki tiedostonimet alkavat numerolla img, jota seuraa numero:
# List of image file names
images = ['img1', 'img2', 'img30', 'img3', 'img22', 'img100']pythonJos käytämme Pythonin sorted(), käytetään leksikografista järjestystä. Tämä käsittelee peräkkäisiä numeroita yksittäisinä numeroina. Näin ollen numerot ['1', '2', '100'] sijoitetaan järjestykseen ['1', '100', '2']. Tulos ei ole odotetun mukainen:
# Sort using lexicographic order
sorted_image = sorted(images)
# Show that it works
assert sorted_image == ['img1', 'img100', 'img2', 'img22', 'img3', 'img30']pythonSyötämme lambda, joka tuottaa avainfunktion, jolla varmistetaan, että lajittelu on oikea. Avainfunktio poimii tiedostonimen numeerisen osan, jota sorted() käyttää avaimena:
# 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']pythonAvainfunktiota käytetään paikallisesti ja vain kerran. Sille ei tarvitse määritellä erillistä nimettyä funktiota. Lambdat ovat oikea tapa luoda avainfunktioita. Katsotaanpa vielä kaksi esimerkkiä.
Kuten sorted(), myös sisäänrakennetut Python-funktiot min() ja max() ottavat vastaan valinnaisen avainfunktion. Funktiot etsivät pienimmän ja suurimman elementin listasta tai muusta iterattavasta. Pienin tai suurin elementti on määritelmäkysymys, ja se voidaan määrittää avainfunktion avulla.
Yksinkertaisten arvojen luetteloissa, kuten numeroluettelossa, on selvää, mitä pienimmällä tai suurimmalla elementillä tarkoitetaan. Tässä tapauksessa emme tarvitse erityistä avainfunktiota:
nums = [42, 69, 51, 13]
assert min(nums) == 13
assert max(nums) == 69pythonJos avainfunktiota ei välitetä, käytetään oletusarvoisesti identiteettifunktiota f(x) = x. Tämä voidaan helposti määritellä Python-lambda-funktiona lambda x: x.
Mutta entä jos jokainen iterattavan elementti sisältää useita päivämääriä? Kuvitellaan lista sanakirjoista, jotka edustavat ihmisiä heidän nimillään ja ikänsä. Mikä on kriteeri min() lle ja max(), kun päätetään, mikä on pienin ja suurin elementti? Tässä tilanteessa avainfunktio on hyödyllinen.
Tarvitsemme esimerkkitietoja havainnollistaaksemme avaintoimintojen toimintaa. Luodaan funktio Person(), joka toimii konstruktorina:
# 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}pythonLuomme luettelon ihmisistä käyttämällä konstruktorifunktiotamme:
# Create list of people
people = [person('Jim', 42), person('Jack', 51), person('John', 69)]pythonEtsimme vanhimman henkilön käyttämällä max(). Tämä luo avainfunktion käyttämällä lambda-lauseketta, joka ottaa henkilön sanakirjan ja poimii siitä iän vertailuelementiksi:
# Find the oldest person
oldest = max(people, key=lambda person: person['age'])
# Check that it works
assert oldest == Person('John', 69)pythonLähestymistapa toimii täsmälleen samalla tavalla min() funktiossa. Tässä tapauksessa määritellään avainfunktio min() kutsun ulkopuolella ja käytetään jälleen lambda-lauseketta. Tämä parantaa luettavuutta ja on hyödyllistä, jos avainfunktiolla on useita paikallisia käyttötarkoituksia:
# 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)pythonKuinka luoda sulkeumia Python-lambdoilla
Python-lambdoja käytetään myös sulkeumien määrittelyssä. Nämä ovat funktioita, jotka luodaan muiden funktioiden avulla ja jotka tallentavat arvon. Sulkeumia voidaan käyttää luomaan samankaltaisten funktioiden ryhmiä. Esitämme yleisen esimerkin, jossa luodaan potenssifunktioita.
Potenssifunktiot ottavat argumentin ja korottavat sen potenssiin. Neliöfunktio f(x) = x ^ 2 ja kuutiofunktio f(x) = x ^ 3 ovat tunnettuja esimerkkejä. Mielivaltaisia potenssifunktioita voidaan luoda sulkeumina käyttämällä konstruktorifunktiota. Käytämme lambda-lauseketta, mikä tarkoittaa, että meidän ei tarvitse määritellä sisäistä nimettyä funktiota:
# 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) == 1000pythonKuinka käyttää välittömästi kutsuttua funktiolauseketta (IIFE) Python-lambdoilla
IIFE, lausutaan “iffy”, on tunnettu malli JavaScriptissä. Siinä määritellään nimetön funktio ja suoritetaan se välittömästi.
Lambdat voidaan käyttää IIFE-lausekkeina, vaikka ne eivät ole kovin hyödyllisiä Pythonin rajoitusten vuoksi. Meidän tarvitsee vain laittaa sulkeet lambda-lausekkeen ympärille:
(lambda num: num * num)pythonJa toinen suluissa oleva argumentti (argumentit):
assert (lambda num: num * num)(3) == 9python