Materjalid koostas ja kursuse viib läbi
Tartu Ülikooli arvutiteaduse instituudi programmeerimise õpetamise töörühm
< eelmine | 6. nädala sisukord | järgmine > |
6.2 Funktsioonil on väärtus
ÜLDISTAMINE. ARGUMENDID
Üsna sageli on meil vaja peaaegu samasugust tegevust teha mitmes erinevas kohas. Kui eri kohtades on vaja sarnast, kuid teatud variatsiooniga koodi, siis on võimalik kirjeldada funktsioon natuke üldisemalt. Nimelt saab funktsiooni kirjeldada nii, et tema väljakutsumisel antakse ette argumendid ja konkreetne tegevus sõltub nende väärtustest.
Näiteks eelmise allalugemise funktsiooni võime teha üldisemaks nii, et anname ette, millisest arvust tuleb hakata lugema. Hetkel läheb programm sellest isegi lühemaks. Nimelt pole meil enam vaja rida i = 10
, vaid lisame hoopis muutuja i funktsiooni nime järel olevatesse sulgudesse.
from time import sleep def loe_alla(i): while i > 0: print(i) i -= 1 sleep(1) loe_alla(4)
Nüüd on funktsioon palju paindlikum ja käitub erinevalt olenevalt argumendi väärtusest. Näites on funktsioon loe_alla välja kutsutud argumendi väärtusega 4. See tähendab, et i saab esialgseks väärtuseks 4. Tsükli jätkamistingimus on täidetud ja nii tehaksegi esimene samm i väärtusega 4, mis väljastatakse ekraanile. Järgmine rida muudab i väärtuse ühe võrra väiksemaks ja nii edasi.
Proovige funktsiooni välja kutsuda erinevate argumentide väärtustega, nt loe_alla(8)
, loe_alla(1)
, loe_alla(-1)
.
Muudame nüüd ridade print(i)
ja i -= 1
järjekorda ja järgmise küsimuse tarbeks kutsume selle funktsiooni välja argumendiga 6.
from time import sleep def loe_alla(i): while i > 0: i -= 1 print(i) sleep(1) loe_alla(6)
Ülesanne
Kokkuvõttev funktsiooni tutvustav video
FUNKTSIOON TAGASTAB VÄÄRTUSE
Eelmised näited olid funktsioonidest, mis n-ö tegid midagi ära. Nüüd vaatame funktsioone, mis tagastavad väärtuse või õieti funktsioon ise ongi selle väärtusega. Tegelikult on see väga sarnane funktsiooni mõiste matemaatilise käsitlusega. Nimelt vastab igale argumendile teatud väärtus, mida nimetataksegi selle funktsiooni väärtuseks antud argumendi korral. Näiteks ruutfunktsiooni x2 korral vastab argumendile 4 funktsiooni väärtus 16, argumendile 5 aga 25. Koosinusfunktsiooni korral vastab argumendile 0 funktsiooni väärtus 1, sest cos(0) = 1. Ruutjuure korral vastab argumendile 9 funktsiooni väärtus 3. Koosinuse ja ruutjuure jaoks on Pythonis funktsioonid olemas, vastavalt cos
ja sqrt
. Nende kasutamiseks tuleb enne nad moodulist math importida (from math import cos, sqrt
).
Proovime aga ise kirjeldada funktsiooni, millega saab leida arvu ruudu ehk siis ruutfunktsiooni x2 väärtuse konkreetse argumendi korral.
def ruutu(x): return x**2 print(ruutu(4))
Pange see programm tööle!
Selliste funktsioonide korral, mis peavad tulemuse tagastama, on olulisel kohal käsk return
, millega funktsioon väärtuse omandabki. Programmi kolmas rida on juba funktsiooni kirjelduse järel ja rakendab vastloodud funktsiooni argumendiga 4. Nüüd on ruutu(4)
väärtus juba 16 ja seda saab kasutada nagu arvu ikka. Näiteks saime selle arvu ekraanile väljastada. Saaksime seda ka avaldises kasutada, nt avaldise ruutu(4) - 17
väärtus oleks -1.
Funktsiooni kirjeldus võib olla pikem, argumente võib olla rohkem (sel juhul eraldatakse need komadega) ja tagastatav suurus võib olla ka muud tüüpi kui arv. Järgmine funktsioon tagastab tõeväärtuse.
def kas_raha_jätkub(kghind, kogus, raha): hind = kghind * kogus if hind <= raha: return True else: return False if kas_raha_jätkub(2, 4.5, 10): print("Ostan")
Kuna selle funktsiooni väärtus on tõeväärtustüüpi, siis saab seda kasutada näiteks valikulause tingimuses. Antud juhul on kas_raha_jätkub(2, 4.5, 10)
väärtuseks True
.
Kui funktsioon võtab mitu argumenti, siis on oluline nende järjestus. Praegusel juhul antakse funktsiooni väljakutsumisel esimese argumendi väärtus muutujale kghind, teise väärtus muutujale kogus ja kolmanda väärtus muutujale raha. Võiks mõelda nii, et kui funktsioon argumentidega 2, 4.5 ja 10 välja kutsutakse, siis enne funktsioonis olevate lausete juurde minemist tehakse järgmised omistuslaused: kghind = 2
, kogus = 4.5
ja raha = 10
. Tuleb ka märkida, et funktsiooni argumentide nimed on programmi seisukohalt suvalised, neist ei sõltu programmi jaoks mitte midagi (nagu ka muutujate nimede puhul), kuid nimed võiksid ikka olla sellised, mis annaksid programmi lugejale kasulikku infot koodi kohta.
Tegelikult on funktsioon kas_raha_jätkub võimalik defineerida kahe reaga (1 rida funktsiooni nime ja argumentide jaoks ning 1 rida return-lause jaoks). Soovi korral püüdke funktsiooni kirjeldus nii ümber kirjutada! (Abiks võib olla teadmine, et return
järel ei pruugi olla ilmutatult True
või False
, vaid näiteks avaldis a * b <= c
.)
Ülesanne
TAGASTAMINE JA VÄLJASTAMINE
Me oleme nendes materjalides kasutanud kahte küllaltki sarnast terminit: väljastamine ja tagastamine. Väljastamise all mõtleme põhiliselt millegi ekraanile manamist (eelkõige funktsiooni print abil). Tagastamise all aga peame silmas funktsiooni väärtuse tagastamist (käsu return abil). (Mingites teistes materjalides võib sõnastus olla teistsugune.) Kui me jaotasime funktsioone sellisteks, mis midagi ära teevad ja sellisteks, mis väärtuse tagastavad, siis kuhu platseerub järgmine funktsioon?
def summa(x,y): print(x + y)
Arvutamine ilmselt toimub. Tulemus aga väljastatakse ekraanile ja seda ei tagastata - return
puudub. Selline funktsioon kvalifitseerub millegi ära tegijate hulka. Selline liigitamine on oluline seepärast, et erinevatel liikidel on mõnevõrra erinevad rollid. Väärtust tagastavad funktsioonid leiavad kasutust seal, kus saab kasutada arve, tõeväärtusi, sõnesid - oleneb sellest, mis tüüpi väärtus tagastatakse. Näiteks ruutu(4)
sobib tehniliselt igale poole, kuhu kõlbaks 16. Igale poole, kuhu sobib True
, sobib tehniliselt ka kas_raha_jätkub(2, 4.5, 10)
. Nende väärtus ongi igal konkreetsel juhul see, mis vastavalt funktsiooni kirjeldusele ja etteantud argumentidele välja arvutatakse ja return-rea abil tagastatakse.
Neid funktsioone, milles return-lauset pole ja mis lihtsalt teevad midagi ära ise mingit väärtust saamata, rakendatakse harilikult iseseisvate lausetena. Neid ei saa kasutada avaldistes.
Proovime ülaltoodud funktsiooni summa korral püüda tema väärtuse ekraanile väljastada.
def summa(x,y): print(x + y) print(summa(1,3))
Proovige see programm tööle panna!
Ekraanile ilmub
4 None
Mis siis juhtus? Kõigepealt käivitati funktsioon summa(1,3)
ja väljastati 1 + 3 ehk 4. Seejärel aga püüti ekraanile väljastada funktsiooni summa(1,3)
väärtus. Kuna aga seal return-i sees pole, väärtust pole ja seda sümboliseerib sõna None (eesti keeles “mitte miski”). Kui tahame teha funktsiooni, mis annab võimaluse summa arvutada ja siis seda summat avaldistes edasi kasutada, siis peaksime kasutama return-lauset.
def summa(x,y): return x + y
Proovige, mis nüüd ekraanile tuleb!
def summa(x,y): return x + y print(summa(1,3))
Samuti on väljastamise ja tagastamise erinevus märgatav, kui tahame funktsiooni väärtust kasutada mingis avaldises. Näiteks keskmise arvutamisel tahaksime summa jagada veel kahega. Proovime seda mõlema variandiga.
def summaReturn(x,y): return x + y print(summaReturn(1,3)/2)
def summaPrint(x,y): print(x + y) print(summaPrint(1,3)/2)
Varem väitsime, et iga funktsiooni väljakutsel toimub esmalt argumendiks antavate väärtuste omistamine funktsiooni argumentidele. Funktsiooni argumentidest võib mõelda kui tavalistest muutujatest, kuid olulise kitsendusega: funktsiooni argumente ei saa kasutada funktsiooni kirjeldusest väljaspool. Proovige järgnevat programmi:
def summa(x,y): tulemus = x + y return tulemus print(summa(1,3)) print(x)
Saate veateate, sest muutujat x ei eksisteeri funktsiooni kirjeldusest väljaspool. Täpselt sama lugu on muutujatega, mis on defineeritud funktsiooni kirjelduses. Näiteks kui püüame rea print(tulemus)
abil väljastada muutuja tulemus väärtust, siis seda saame teha vaid funktsiooni kirjelduses, väljaspool funktsiooni kirjeldust muutujat nimega tulemus ei eksisteeri. (Lokaalsetest ja globaalsetest muutujatest tuleb põhjalikumalt juttu järgmises peatükis.)
Ülesanne
PERE SISSETULEKU NÄIDE ILMA FUNKTSIOONITA JA FUNKTSIOONIGA
Vaatleme programmi, mis küsib isa brutopalga, ema brutopalga ning alaealiste laste arvu, ja arvutab selle põhjal pere kuusissetuleku. (Oletame, et iga alaealise lapse kohta makstakse toetust 20€ kuus.)
Esialgu võib eeldada, et mõlema vanema kuupalk on vähemalt sama suur kui maksuvaba miinimum.
Järgnevates videotes on see ülesanne lahendatud vastavalt ilma uut funktsiooni defineerimata ja uue funktsiooni defineerimisega . Videotes ei ole kasutatud keskkonda Thonny, kasutatud on keskkonda IDLE. Kuna videod on valminud juba mõni aasta tagasi, siis rahasummad ei pruugi olla tõepärased.
Kontrollülesannetest
Selle materjali põhjal peaks lahendatav olema kontrollülesanne 6.2.
< eelmine | 6. nädala sisukord | järgmine > |