Lista funktion parametrina ja funktion palauttamana arvona
Edellä esitetty ohjelma toimii täysin oikein, mutta sitä voi vielä selkeyttää jakamalla pääohjelmassa esiintyviä toimintoja sopiviin funktioihin.
Lämpötilalistan luominen ja arvojen lukeminen siihen on yksi
kokonaisuus, joka sopii hyvin omaksi funktiokseen kysy_lampotilat
.
Tieto perustetusta listasta ja siihen tallennetuista lämpötiloista pitää
kuitenkin saada jotenkin pääohjelman käyttöön. Tähän on kaksi keinoa.
Toinen on luoda lista pääohjelmassa ja antaa lista sitten parametrina
siihen lämpötilat tallentavalle funktiolle. Parametrina annettuun
listaan tehdyt muutokset ja lisäykset näkyvät myös pääohjelmassa. Tästä
kerrotaan tarkemmin kierroksen 6 luvussa Arvot ja viittaukset.
Toinen tapa on luoda lista funktiossa kysy_lampotilat
ja palauttaa
tämä lista funktion lopussa. Aivan samalla tavalla kuin funktion
palauttama lukuarvo voidaan ottaa käyttöön pääohjelmassa, myös funktion
palauttama lista voidaan ottaa käyttöön pääohjelmassa. Seuraavassa
esimerkissä on käytetty tätä tapaa:
def kysy_lampotilat():
LKM = 30
lampotilat = [0.0] * LKM
i = 0
print("Anna", LKM, "lampotilaa")
while i < LKM:
lampo = float(input("Seuraava lampotila: "))
lampotilat[i] = lampo
i += 1
return lampotilat
Pääohjelmassa funktiota voidaan kutsua esimerkiksi seuraavasti:
lampolista = kysy_lampotilat()
Tällöin muuttuja lampolista
saa arvokseen funktion
kysy_lampotilat
palauttaman listan, joka sisältää käyttäjän antamat
lämpötilat.
Vastaavasti voidaan kirjoittaa oma funktio listassa olevien lämpötilojen tulostamiseen:
def tulosta_lampotilat(lammot):
print("Annetut lampotilat")
for arvo in lammot:
print(arvo)
Funktio saa parametrina listan, joka sisältää aikaisemmin luetut
lämpötilat. Funktiossa oleva for
-käsky käy tämän listan läpi ja
tulostaa jokaisen siinä olevan lämpötilan. Funktiota voidaan kutsua
pääohjelmasta esimerkiksi seuraavasti:
tulosta_lampotilat(lampolista)
Jos pääohjelman muuttujaan lampolista
on aikaisemmin sijoitettu
luetut lämpötilat sisältävä lista, niin funktiota tulosta_lampotilat
suoritettaessa parametri lammot
tarkoittaa tätä samaa listaa.
Kirjoitetaan myös funktio keskiarvon laskemista varten. Keskiarvon laskemista ei ole tässä sisälletetty lämpötilat tulostavaan funktioon kahdesta syystä: Ensiksi, keskiarvon laskeminen on selvästi lämpötilojen tulostamisesta erillinen toimenpide. Kun kirjoitamme funktion jonkin asian suorittamista varten, on selvempää, että funktio tekee juuri tämän asian eikä sen oheen ole liitetty funktion alkuperäiseen tarkoitukseen liittymättömiä asioita. Toiseksi, lämpötilojen tulostaminen sisältää selkeästi ohjelman käyttöliittymään liittyviä asioita, kun taas keskiarvon laskemiseen ei liity kommunikointia ohjelman käyttäjän kanssa. On järkevää erottaa toisistaan ohjelman sellaiset osat, jotka kommunikoivat käyttäjän kanssa ja sellaiset, jotka suorittavat puhdasta laskentaa. Tällöin ohjelman muuttaminen myöhemmin on helpompaa, jos halutaan muuttaa ohjelman käyttöliittymä toisenlaiseksi (esimerkiksi vaihtaa nyt ohjelmassa käytössä oleva tekstipohjainen käyttöliittymä graafiseen käyttöliittymään).
Keskiarvon laskemisessa tarvitaan listassa olevien lämpötilojen määrä.
Funktiossa kysy_lampotilat
on tätä varten määritelty vakio LKM
,
mutta toisessa funktiossa määritelty vakio ei näy toisen funktion
sisällä, eikä vakiota voida näin ollen suoraan käyttää funktiossa
laske_keskiarvo
. Yksi vaihtoehto on siirtää vakiolle LKM
arvon
antava sijoituskäsky LKM = 30
funktioiden ulkopuolelle. Tällöin
vakio on käytettävissä kaikissa samaan tiedostoon kirjoitetuissa
funktioissa. Tässä tapauksessa siirto on kuitenkin tarpeeton, koska
listassa olevien lämpötilojen määrän saa selville helposti myös ilman
vakiota. Pythonissa on listoja varten valmis funktio len
, joka
palauttaa funktiolle parametrina annetun listan pituuden. Listan
lampotilalista
pituuden saa siis selville ilmauksella
len(lampotilalista)
.
Aina jakolaskuja suoritettaessa on hyvä tarkistaa se, että jakaja ei ole
nolla, koska nollalla jakaminen aiheuttaisi ohjelman kaatumisen.
Funktiossa laske_keskiarvo
on myös tämä mahdollisuus otettu
huomioon. Jos lämpötilojen määrä on 0, funktio palauttaa arvon 0.0.
Pääohjelmassa on kutsuttu keskiarvon laskevaa funktiota (lampolista
on jälleen annetttu funktiolle parametrina) ja tulostettu funktion
palauttama arvo. Seuraavaksi koko ohjelma:
def kysy_lampotilat():
LKM = 30
lampotilat = [0.0] * LKM
i = 0
print("Anna", LKM, "lampotilaa")
while i < LKM:
lampo = float(input("Seuraava lampotila: "))
lampotilat[i] = lampo
i += 1
return lampotilat
def tulosta_lampotilat(lammot):
print("Annetut lampotilat")
for arvo in lammot:
print(arvo)
def laske_keskiarvo(lampotilalista):
summa = 0.0
for lampotila in lampotilalista:
summa += lampotila
lukumaara = len(lampotilalista)
if lukumaara > 0:
keskiarvo = summa / lukumaara
else:
keskiarvo = 0.0
return keskiarvo
def main():
lampolista = kysy_lampotilat()
tulosta_lampotilat(lampolista)
keskiarvo = laske_keskiarvo(lampolista)
print(f"Lampotilojen keskiarvo on {keskiarvo:.2f}.")
main()
Annetussa ohjelmassa on käytetty useita eri muuttujia ja parametreja, joiden arvona on lämpötilat sisältävä lista. Kunkin funktion sisällä listaan käydään käsiksi oman muuttujan tai parametrin kautta. Asian selventämiseksi esimerkissä on käytetty jokaisessa funktiossa tuolle muuttujalle tai parametrille eri nimeä. Yhdessä funktiossa määritelty nimi ei näy suoraan toisessa funktiossa, mutta tiedon käsiteltävästä listasta voi välittää funktiolta toiselle parametrien ja paluuarvojen välityksellä.
Seuraavassa animaatiossa on vielä esimerkki samantapaisen, mutta vähän
lyhyemmän ohjelman suorituksesta. Tarkkaile erityisesti parametrien ja
pääohjelman lampolista
-muuttujan käyttöä ohjelmassa. Animaation
lyhentämiseksi listan alkioiden määrän tarkistus on jätetty pois keskiarvoa
laskettaessa.
Käytännön ohjelmoinnissa eri funktioissa käytetään samaa asiaa
tarkoittavasta parametrista kuitenkin usein samaa muuttujan ja
parametrin nimeä, vaikka Python-ohjelman kannalta kysymys on useasta eri
muuttujasta tai parametrista. Käytännössä esimerkiksi lämpötilaohjelma
kirjoitettaisiin usein niin, että käytössä olisi lämpötilat sisältävälle
listalle vain yksi nimi, lampotilat
, jota käytettäisiin sekä
parametrina funktioissa kysy_lampotilat
, tulosta_lampotilat
ja
laske_keskiarvo
että muuttujana main
-funktiossa. Kysymys ei
olisi kuitenkaan yhdestä muuttujasta, vaan kolmesta eri parametrista ja
yhdestä muuttujasta, joilla kaikilla vain on sama nimi. Tieto
käsiteltävästä listasta välittyisi edelleen parametrien ja funktioiden
paluuarvojen välityksellä. Tässä monisteessa on kuitenkin pyritty aluksi
käyttämään eri parametreille eri nimiä, jotta aloittelijan olisi
helpompi nähdä, milloin on kysymys samasta ja milloin eri muuttujasta.
Tarkastellaan seuraavaksi esimerkkiä hieman monimutkaisemmasta listan
läpikäynnistä. Haluamme selvittää, kuinka moni listassa olevista
lämpötiloista on vähintään yhtä suuri kuin käyttäjän antama raja.
(Tällaista toimintoa voidaan käyttää esimerkiksi hellepäivien määrän
selvittelyyn.) Kirjoitetaan oma funktio montako_yli_rajan
, joka käy
sille parametrina annetun listan läpi ja tarkistaa jokaisen listassa
olevan lämpötilan kohdalla, onko kyseinen lämpötila suurempi tai
yhtäsuuri kuin funktiolle toisena parametrina annettu raja. Tarkistus
onnistuu siten, että kirjoitamme toistokäskyn sisään if
-käskyn, joka
tekee tarvittavan tarkastuksen jokaisella kierroksella. Lisäksi
tarvitaan laskuri, joka pitää kirjaa siitä, kuinka monta tarpeeksi
suurta lämpötilaa on jo kohdattu. Tämä laskuri alustetaan aluksi
nollaksi ja sitä kasvatetaan aina, kun listasta löydetään annettua rajaa
suurempi tai yhtäsuuri luku. Kun koko lista on käyty läpi, funktio
palauttaa laskurin arvon.
def montako_yli_rajan(lampotilojen_lista, raja):
ylittavien_maara = 0
for asteet in lampotilojen_lista:
if asteet >= raja:
ylittavien_maara += 1
return ylittavien_maara
Arvon palauttava return
-käsky on kirjoitettava toistokäskyn
ulkopuolelle. Jos käsky olisi for-käskyn sisällä, arvo palautettaisiin
(ja funktion suoritus lopetettaisiin) jo siinä vaiheessa, kun listan
ensimmäinen alkio on tutkittu ja listan loppuosaa ei ole vielä käyty
lainkaan läpi.
Funktiota voidaan käyttää esimerkiksi lisäämällä pääohjelmaan seuraavat käskyt:
lamporaja = float(input("Anna raja, jonka ylittavat lampotilat lasketaan: "))
paiva_lkm = montako_yli_rajan(lampolista, lamporaja)
print("Raja ylittyi", paiva_lkm, "paivana.")
Toinen tyypillinen esimerkki listan läpikäynnistä on tilanne, jossa
halutaan etsiä listasta parhaiten jonkin ehdon täyttävä arvo,
esimerkiksi listan korkein lämpötila. Tällöin listaa läpikäydessä
käytetään apumuuttujaa, johon tallennetaan korkein tähän asti löydetty
lämpötila. Ennen läpikäyntiä apumuuttujan arvoksi sijoitetaan joko
listan ensimmäinen alkio (jos tiedetään, että lista ei ole tyhjä) tai
sitten niin pieni arvo, että se ei voi olla minkään päivän lämpötila.
Sitten käydään lista läpi alkio kerrallaan. Jos tarkasteltavan alkion
arvo on suurempi kuin apumuuttujan arvo, päivitetään apumuuttujan arvo.
Kun lista on käyty kokonaan läpi, apumuuttuja sisältää koko listan
korkeimman lämpötilan. Alla esimerkkinä funktio etsi_maksimi
, joka
käy sille parametrina annetun listan läpi ja etsii ja palauttaa
korkeimman siitä löytyneen lämpötilan. Jos lista on tyhjä, funktio
palauttaa erikoisarvon None
.
def etsi_maksimi(lampotilalista):
if len(lampotilalista) == 0:
return None
else:
maksimi = lampotilalista[0]
for lampotila in lampotilalista:
if lampotila > maksimi:
maksimi = lampotila
return maksimi
Funktiota voidaan kutsua ja sen paluuarvo tulosta lisäämällä pääohjelmaan esimerkiksi seuraavat rivit:
maksimilampotila = etsi_maksimi(lampolista)
print("Korkein lampotila on ", maksimilampotila)
Huomautus: Pythonissa on myös valmis funktio max
, joka etsii ja palauttaa suurimman arvon parametrina
annetusta listasta. Yllä esitettyä periaatetta voi kuitenkin käyttää myös muissakin tilanteissa, joissa etsitään
listasta jollain kriteerillä halutuinta alkiota, esimerkiksi alkiota, joka on lähimpänä parametrina annettua arvoa: Käytetään
apumuuttujaa, jonka arvona on tähän asti löydetty paras alkio. Käydään läpi listaa alkio kerrallaan ja tutkitaan,
onko vuorossa oleva alkio (käytetyllä kriteerillä) parempi kuin apumuuttujassa oleva arvo. Jos näin on, päivitetään
apumuuttujan arvoa.