Materjalid koostas ja kursuse viib läbi
Tartu Ülikooli arvutiteaduse instituudi programmeerimise õpetamise töörühm
< eelmine | 6. nädala sisukord | järgmine > |
6.3 Argumendid, muutujad
MITU FUNKTSIOONI KOOS
Vaatame näiteid, kus funktsioone kasutatakse nii, et ühe väärtus on teise argumendiks.
ümardatud_sisestatud_arv = round(float(input("Sisestage arv "))) print("See arv ümardatult on " + str(ümardatud_sisestatud_arv))
Olge head ja testige seda suhteliselt kokkusurutud programmi.
Selle esimene rida teeb tegelikult palju asju. Tegevus algab “seestpoolt”.
- Funktsiooniga input küsitakse kasutaja käest arv. Funktsiooni input väärtus on sõne tüüpi.
- Funktsioon float võtab argumendiks sõne ja tema enda väärtuseks saab vastav ujukomaarv (murdarv). (Teiste sõnadega: Funktsioon tagastab vastava ujukomaarvu. Või veel kõnekeelsemalt: Funktsioon muudab sõne vastavaks ujukomaarvuks.)
- Funktsioon round võtab argumendiks ujukomaarvu ja ümardab selle täisarvuks.
Lõpuks määratakse see täisarv muutuja ümardatud_sisestatud_arv väärtuseks.
Niimoodi teise funktsiooni argumendiks saab olla ainult väärtust tagastav funktsioon. Sellisena saab muidugi kasutada ka isekirjeldatud funktsioone, nt
def summa(x,y): return x + y a = summa(summa(1, 3)*2, 4)
Kokkuvõtva ülevaate eelmisest näiteprogrammist annab järgmine video
Ülesanne
ARGUMENTIDEST VEEL
Eelnevates näidetes olid meil argumentideks tavaliselt arvud või sõned, vastavalt konkreetsele funktsioonile muidugi. Olenevalt funktsioonist võivad argumendid olla ka hoopis muud tüüpi. Nagu juba eespool nägime, võib argumentide arv olla funktsioonidel ka erinev. Samuti ei pea argumendid olema omavahel sama tüüpi.
Koostame funktsiooni, mille argumendiks on fail ja tagastatakse sõnede järjend, mille elemendid on read sellest failist.
def failistSõnejärjendisse(fail): järjend = [] for rida in fail: järjend += [rida.strip()] # järjend.append(rida.strip()) # strip() võtab lõpust ära reavahetuse fail.close() return järjend
Eks me saime ju nö otse failistki for-tsükli abil ridahaaval toimetada. Nüüd aga saame järjendi elemendile (mis vastab faili reale) ka indeksi abil juurde. Samuti oleme reavahetuse ka rea lõpust eemaldanud.
def failistSõnejärjendisse(fail): järjend = [] for rida in fail: järjend += [rida.strip()] # järjend.append(rida.strip()) # strip() võtab lõpust ära reavahetused fail.close() return järjend failinimi = input("Sisestage failinimi ") fail = open(failinimi, encoding="UTF-8") sõned = failistSõnejärjendisse(fail) print(sõned) print(sõned[3])
See funktsioon tagastas järjendi. See on üheks võimalikuks viisiks mitme väärtuse tagastamiseks. Nimelt saab tegelikult alati tagastada vaid ühe väärtuse. Kui on mitut vaja tagastada, tuleb kasutada sobivat andmestruktuuri, mis siis ühena teisi hõlmab.
Mõnikord on konkreetse argumendi väärtus peaaegu alati sama ja oleks tüütu seda alati uuesti ette anda. Sellisel juhul saame kasutada vaikeväärtust. Kui funktsiooni väljakutsel pole seda argumenti näidatud, siis saab argumendi väärtuseks vaikeväärtus.
def kasKiiruseÜletamine(kiirus, piirkiirus = 90): return kiirus > piirkiirus print(kasKiiruseÜletamine(100)) print(kasKiiruseÜletamine(90, 70))
Vaikeväärtus on ka funktsiooni print
argumendil end
. Nimelt vaikimisi vahetab print
rida, argument end = "\n"
. Võime aga ka ise selle argumendi väärtuse ette anda.
print("Väljastatav tekst ", end = "lõppu juurde")
Sõnedega oleme kasutanud ka funktsioone, mis on sõnega ühendatud punktiga.
print("tartu".capitalize()) print("Tartu".endswith("tu")) print("Tartu".upper()) linn = "Tartu" print(linn.lower())
Tundub nagu oleks sellisel juhul argument mitte sulgudes vaid hoopis funktsiooni ees. Põhimõtteliselt see nii ongi. Selliseid funktsioone nimetatakse meetoditeks ja need on väga tavalised objektorienteeritud programmeerimises. Meie siin kursusel kasutame meetodeid küll (just eriti sõnede puhul), aga põhjalikum käsitlus jääb selle kursuse raamest välja.
LOKAALSED JA GLOBAALSED MUUTUJAD
Olgu meil programm, milles on defineeritud funktsioon ja siis seda rakendatud.
def summaFunktsioon(a, b, c): summa = a + b + c return summa print(summaFunktsioon(1, 2, 3))
Pannes programmi tööle saame ekraanile arvu 6, mis muidugi ongi 1 + 2 + 3 korral oodatud.
Lisame programmile rea print(summa)
.
def summaFunktsioon(a, b, c): summa = a + b + c return summa print(summaFunktsioon(1, 2, 3)) print(summa)
Saame veateate, mis väidab, et NameError: name 'summa' is not defined
. Nimi summa
ei ole defineeritud (kirjeldatud). Kuna funktsiooni sees toimuv on funktsiooni "siseasi", siis tõepoolest muutujat summa
pole väljaspool funktsiooni olemas. Sellist funktsiooni kehas (kirjelduses) defineeritud muutujat nimetatakse lokaalseks muutujaks. Kui tõstame printimise funktsiooni kirjelduse sisse, siis on kõik korras.
def summaFunktsioon(a, b, c): summa = a + b + c print(summa) return summa print(summaFunktsioon(1, 2, 3))
Esimene 6 tuleb ekraanile print(summa)
toimel ja teine 6 print(summaFunktsioon(1, 2, 3))
toimel.
Samuti on lokaalsed ka funktsiooni argumendid. Muutuja b
on funktsiooni sees täiesti olemas.
def summaFunktsioon(a, b, c): summa = a + b + c print(b) return summa print(summaFunktsioon(1, 2, 3))
Funktsioonist väljas aga mitte.
def summaFunktsioon(a, b, c): summa = a + b + c return summa print(summaFunktsioon(1, 2, 3)) print(b)
Lokaalsed muutujad luuakse funktsiooni igal käivitamisel uuesti ja nad hävivad, kui funktsioon töö lõpetab. Lokaalsed muutujad on funktsiooni siseasi, väljast neid näha pole. Neile saab panna sama nime, mis juba programmi põhiosas kasutuses (või mõnes teises funktsioonis kasutuses olnud).
Näiteks on järgmises programmis nii funktsioonis kui põhiprogrammis muutuja summa
.
def summaFunktsioon(a, b, c): summa = a + b + c return summa summa = 10 print(summaFunktsioon(1, 2, 3)) print(summa)
Näeme, et viimases reas on muutuja summa
väärtus just see, mis ta põhiprogrammis sai - funktsioonis toimuv tema väärtust ei muuda.
Põhiprogrammis defineeritud muutujad on globaalsed muutujad. Nende väärtusi saab kasutada nii põhiprogrammis kui ka funktsioonide sees. Kui aga funktsioonis on sama nimega lokaalne muutuja, siis globaalset muutujat seal kasutada ei saa. Eelmises näites just nii oligi.
Järgmises näites aga saab globaalset muutujat funktsioonis kasutada, sest sellenimelist lokaalset muutujat funktsioonis pole.
def summaFunktsioon(a, b, c): summa = a + b + c + gm return summa gm = 17 # globaalne muutuja print(summaFunktsioon(1, 2, 3))
Teatud juhtudel on globaalsete muutujate kasutamine funktsioonis ebasoovitav ja nii võib näiteks ka kontrollülesannete automaatkontrolli tagasiside sellele tähelepanu juhtida.
KOKKUVÕTE
Funktsioonid e. alamprogrammid võimaldavad (sageli küllalt keerulise) programmilõigu panna kirja ühekordselt, aga kasutada seda mitmes erinevas kohas.
Funktsiooni definitsiooni (kirjelduse) e def-lause kehas olevad laused jäetakse esialgu lihtsalt meelde. Neid saab hiljem käivitada, kirjutades funktsiooni nime koos sulgudega. Sellist tegevust nimetatakse funktsiooni väljakutseks e rakendamiseks.
Funktsiooni defineerimisel saab jätta mõned detailid lahtiseks. Täpne töö sõltub etteantud argumentide väärtustest.
Funktsioone võib jaotada kahte gruppi – ühed teevad midagi ära ja teised arvutavad ja tagastavad midagi.
Selleks, et funktsiooni saaks kasutada avaldises, peab ta arvutatud väärtuse tagastama. Väärtuse tagastamiseks kasutatakse võtmesõna return
.
Programmi põhiosas defineeritud muutujaid nimetatakse globaalseteks muutujateks, funktsiooni sees defineeritud muutujaid lokaalseteks muutujateks.
Kontrollülesannetest
Nüüd peaks käes olema info kontrollülesannete 6.3 ja ka 6.4a, 6.4b ning 6.4c lahendamiseks.
< eelmine | 6. nädala sisukord | järgmine > |