3. Tingimus- ja korduslaused¶
Eelmise peatüki programmidega töötas Python täiesti tuimalt – alustas esimesel real oleva lausega, iga rea täitmise järel võttis ette järgmise rea, kuni jõudis programmi lõppu – programmi käik oli täielikult ette ennustatav. Taolisest lähenemisest piisab paraku vaid väga lihtsate ülesannete puhul.
Antud peatükis vaatame, kuidas panna Python valikuid tegema. Selleks täiendame oma arsenali kahe uue lausetüübiga, mille abil on võimalik määrata mingite teiste lausete käivitamise tingimused.
Õpinipp. Ole aktiivne!
Proovi olla materjalist sammu võrra ees, märgates seoseid ja võimalusi enne, kui õpik neid mainib. Iga näite juures loe esimese asjana programmi tekst hoolikalt läbi ja ennusta, mida iga rida teeb.
Teisisõnu, eelista värsket mõttetoitu – see annab parema vormi kui juba läbimälutud tarkuseterad!
Tingimuslause e if
-lause¶
Peaaegu kõikides mittetriviaalsetes programmides tuleb mingil hetkel teha valik, kas jätkata üht- või teistmoodi. Python võimaldab programmeerijal taolised dilemmad panna kirja tingimuslause e valikulause e if-lause abil.
Järgnevas näiteskriptis kasutatakse tingimuslauset arvu absoluutväärtuse arvutamiseks:
arv_tekstina = input('Palun sisesta mingi arv: ')
arv = float(arv_tekstina)
if arv < 0:
# kui oli tegemist negatiivse arvuga,
# siis salvestan vastuse jaoks mõeldud muutujasse antud arvu vastandväärtuse
vastus = -arv
else:
# vastasel juhul on vastuseks esialgne väärtus ise
vastus = arv
print('Selle arvu absoluutväärtus on ' + str(vastus))
Selles programmis ei täida Python enam kõiki käske – see, kas täidetakse käsk vastus = -arv
või vastus = arv
, sõltub konkreetsest kasutaja poolt sisestatud arvust. Antud näites on mõlemas tingimuslause harus vaid üks käsk, aga neid võib seal olla ka rohkem.
Tingimuslause komponendid on päis (if
-i ja tingimusega rida), then
-haru (päisele järgnevad paremale nihutatud read), võtmesõna else
ning else
-haru (jällegi paremale nihutatud).
Tingimusi saab (muuhulgas) moodustada järgmiste operaatoritega:
<
,>
,<=
,>=
sobivad arvude võrdlemiseks;- topeltvõrdusmärk (
==
) tähistab võrdsust nii arvude kui ka sõnede puhul; !=
tähistab mittevõrdsust nii arvude kui ka sõnede puhul.
Märkus
Ära unusta, et üksikut võrdusmärki (=
) kasutatakse Pythonis muutujale väärtuse omistamiseks, seetõttu on võrdsuse kontrollimiseks ette nähtud topeltvõrdusmärk (==
).
Harjutus. Jaguvus.¶
Kirjuta programm, mis küsib kasutajalt kaks arvu ning vastab, kas esimene arv jagub teisega või mitte.
Vihje
Tuleta meelde, mida teeb operaator %
.
Vihje
>>> 6 % 4
2
>>> 6 % 3
0
>>> 4 % 3
1
>>> 4 % 2
0
>>> 4 % 4
0
>>> 4 % 1
0
Treppimine¶
if
-lause kasutamisel on vaja pöörata tähelepanu tühikutele – tühikutega joondamine e treppimine määrab, millised käsud kuuluvad tingimuslause alla ja millised mitte:
nimi = input("Mis su nimi on? ")
if nimi == "Imelik":
print("Tõesti?")
print("Imelik nimi!")
else:
print("Tere, " + nimi + "!")
print("Meeldiv tutvuda!")
Antud näites kuuluvad tingimuslause then-harusse laused print("Tõesti?")
ja print("Imelik nimi!")
ning else-harusse üksainus lause print("Tere, " + nimi + "!")
. Võib ka öelda, et need joondatud laused kuuluvad if
-lause alla – nende käivitamine sõltub if
-lausest.
Programmi viimane lause ei ole trepitud ja seetõttu ei ole ta millegi alluvuses, vaid on täiesti iseseisev. (Kontrollküsimus: kuidas muutuks programmi käitumine, kui ka viimase rea ette panna 4 tühikut?)
Edaspidi näeme, et treppimist kasutatakse ka teistes Pythoni konstruktsioonides ning põhimõte on alati selles, et sama kaugele joondatud järjestikused read moodustavad mingi terviku.
NB!
Trepitud plokile eelnev rida lõpeb alati kooloniga (see on Pythonile lisakinnituseks, et programmeerija soovib järgmisel real alustada trepitud plokki).
Katsetus
Proovi järele, kuidas Python käitub, kui unustad kasutada koolonit või jätad ära mõne taandrea. Sellega saad end taoliseks situatsiooniks juba ette valmistada.
Märkus
Kuigi Python on treppimise osas võrdlemisi paindlik, tuleks segaduste vältimiseks alati kasutada joondamiseks 4 tühikut. Thonnys või IDLE’is kirjutades võib treppimiseks vajutada ka TAB klahvi – keskkond genereerib sellepeale TAB sümboli asemel 4 tühikut. Tegelikult pole enamasti vaja isegi TAB klahvi kasutada – kui vajutada kooloniga lõppeval real uue rea saamiseks ENTER-it, taipab redaktor ise, et järgmine rida tuleb treppida ja lisab uue rea algusesse vajaliku arvu tühikuid. Ka järgmistele ridadele pannakse usinalt tühikud ette. Andmaks märku, et uus rida enam tingimuse alla ei kuulu, tuleb need tühikud ära kustutada ja alustada käsu kirjutamist jälle ekraani vasakust servast.
Harjutus. Eurokalkulaator vol 2¶
Eelmises peatükis oli ülesanne, kus tuli kirjutada eurokalkulaator, mis teisendas kroone eurodeks.
Täienda seda programmi nüüd nii, et see küsiks kasutajalt lisaks rahasummale ka selle, kas ta soovib teisendada Eesti kroone eurodeks või vastupidi.
Vihje
...
algyhik = input("Kas sinu summa on eurodes (EUR) või kroonides (EEK) ?")
...
Proovi kirjutada sellest programmist kaks varianti erinevate kitsendustega:
- esimeses programmis kasutatakse muutujale omistamist ainult ühes kohas;
- teises programmis kasutatakse
print
käsku ainult ühes kohas.
Vihje
...
if ... :
print(...)
else:
print(...)
...
vs
...
if ... :
tulemus = ...
else:
tulemus = ...
print(...)
Näide. Tingimuslaused üksteise sees¶
Tingimuslauseid võib panna üksteise sisse:
arv1 = int(input("Sisesta esimene arv: "))
arv2 = int(input("Sisesta teine arv: "))
if arv1 > arv2:
print("Esimene arv on suurem")
else:
if arv2 > arv1:
print("Teine arv on suurem")
else:
print("Arvud on võrdsed")
Põhimõte on sama nagu lihtlausete allutamisel – alluvuse tähistamiseks lisatakse vastavate ridade algusesse 4 tühikut. Kui alluvatel endal on alluvaid, siis võibki mõne rea ette sattuda 8, 12, üldisemalt n * 4 tühikut.
Märkus
Nüüd peaks olema ka näha, miks treppimist nimetatakse treppimiseks – kui joondamine toimub mitmel tasemel, siis paistab nagu programmi tekst paikneks trepiastmetel.
Harjutus. Tiitlid¶
Kirjuta programm, mis küsib kasutajalt tema nime, perekonnaseisu (vallaline või abielus), sugu ja vanust. Väljasta nende andmete põhjal sobiv tervitus (nt abielus naiste puhul kasuta tiitlit proua, teatud vanusest vanemate meeste puhul härra jne).
Lisavõimalus: üheharuline if
-lause¶
Tingimuslauses võib else
osa ära jätta – seda kasutatakse siis, kui tingimuse mittekehtimise puhul ei ole vaja midagi teha:
x = int(input("Sisesta esimene arv: "))
y = int(input("Sisesta teine arv: "))
print("Arvude erinevus on " + str(abs(x-y)))
if x == y:
print("... järelikult on nad võrdsed")
Harjutus. Miks on ronk nagu kirjutuslaud?¶
Kirjuta järgnev programm ümber nii, et ta töötaks samamoodi nagu enne, aga et seal kasutataks vaid üheharulist if
-lauset:
vastus = input("Miks on ronk nagu kirjutuslaud? ")
if vastus == 'ei tea':
print("Hmm ...")
print("Ma ka ei tea!")
else:
print("Hmm ...")
Lisavõimalus: mitmeharuline if
-lause¶
Üritame panna kirja programmi, mis küsib kasutajalt kuu numbri ja väljastab sellele vastava kuu nime:
kuu = int(input("Sisesta kuu number: "))
if kuu == 1:
print("jaanuar")
else:
if kuu == 2:
print("veebruar")
else:
if kuu == 3:
print("märts")
else:
if kuu == 4:
print("aprill")
else:
if kuu == 5:
print("mai")
else:
if kuu == 6:
print("juuni")
else:
if kuu == 7:
print("juuli")
else:
if kuu == 8:
print("august")
else:
if kuu == 9:
print("september")
else:
if kuu == 10:
print("oktoober")
else:
if kuu == 11:
print("november")
else:
if kuu == 12:
print("detsember")
else:
print("vale kuu number!")
Selles koodis on kõik õige ja loogiline, aga nii kaugele trepitud koodiga on ebamugav toimetada. Õnneks on Pythonis taoliste juhtumite jaoks olemas alternatiivne esitusviis:
kuu = int(input("Sisesta kuu number: "))
if kuu == 1:
print("jaanuar")
elif kuu == 2:
print("veebruar")
elif kuu == 3:
print("märts")
elif kuu == 4:
print("aprill")
elif kuu == 5:
print("mai")
elif kuu == 6:
print("juuni")
elif kuu == 7:
print("juuli")
elif kuu == 8:
print("august")
elif kuu == 9:
print("september")
elif kuu == 10:
print("oktoober")
elif kuu == 11:
print("november")
elif kuu == 12:
print("detsember")
else:
print("vale kuu number!")
Appi tuli võtmesõna elif
, mis on nii kirjapildi kui ka tähenduse poolest kombinatsioon else
’ist ja talle järgnevast if
-ist.
Kogu if-elif-...-else
konstruktsioon moodustab Pythoni jaoks ühe terviku – niipea kui ülevalt alla liikudes leitakse tingimus, mis kehtib, täidetakse vastav haru ja sellega on ka kogu konstruktsioon täidetud. Teisisõnu, if-elif-...-else
’is täidetakse alati täpselt üks haru, nagu ka if-else
puhul. (Kui else
haru kirjutamata jätta, siis võib muidugi juhtuda, et ei täideta ühtegi haru.)
Märkus
Kuigi antud näites on igas elif
plokis ainult üks lause, võib seal olla ükskõik kui keeruline kood, nagu ka if
või else
plokis.
Harjutus. Hinde arvutamine¶
Ülikoolis on tavaks panna hindeid järgmise skeemi järgi:
Tulemus (%) | Hinne |
---|---|
>90 .. 100 | A |
>80 .. 90 | B |
>70 .. 80 | C |
>60 .. 70 | D |
>50 .. 60 | E |
<=50 | F |
Kirjuta programm, mis küsib kasutajalt, mitu punkti võis aines saada, mitu punkti tudeng sai, ning väljastab vastava hinde.
Vihje
Näitelahendus
maks_punkte = int(input("Kui palju punkte oli võimalik saada? "))
punkte = int(input("Kui palju punkte tudeng sai? "))
protsent = punkte / maks_punkte * 100
if protsent > 90:
hinne = 'A'
elif protsent > 80:
hinne = 'B'
elif protsent > 70:
hinne = 'C'
elif protsent > 60:
hinne = 'D'
elif protsent > 50:
hinne = 'E'
else:
hinne = 'F'
print("Nende punktidega saab hindeks " + hinne)
Korduslause e while
-lause¶
Kui meil on vaja teha sama toimingut mitu korda järjest, siis võiks arvata, et programmi tuleb kirjutada laused lihtsalt mitmekordselt nagu järgmises programmis, mis joonistab kilpkonnaga ruudu:
from turtle import *
küljepikkus = 100
forward(küljepikkus)
left(90)
forward(küljepikkus)
left(90)
forward(küljepikkus)
left(90)
forward(küljepikkus)
left(90)
exitonclick()
Selline lahendus muutub väga kohmakaks, kui korduste arv läheb suureks. Pealegi, kui sooviksime kirjutada üldisema programmi, mis joonistab n küljega hulknurga vastavalt kasutaja poolt sisestatud n väärtusele, siis jääksime hätta, kuna me ei tea, mitu korda tuleks ühe külje joonistamise ja pööramise käske kirjutada.
Siinkohal tulevad appi tsüklid (e korduslaused), mis on programmikonstruktsioonid käskude kordamiseks. Selles peatükis vaatame while-lauset, mis kordab tema alluvusse paigutatud lauseid niikaua, kuni teatud tingimus kehtib.
while
-lausega saaksime ruudu joonistamise programmi panna kirja järgnevalt:
from turtle import *
# selle muutuja abil peame arvet, mitu külge on juba joonistatud
joonistatud_kylgi = 0
while joonistatud_kylgi < 4:
forward(100)
left(90)
joonistatud_kylgi = joonistatud_kylgi + 1 # suurendame muutuja väärtust
exitonclick()
while
-lause keha täidetakse vaid siis, kui päises antud tingimus kehtib. Selles suhtes on while
väga sarnane üheharulise if
-lausega. Erinevus on selles, et kui kehas olevad laused on täidetud, siis minnakse uuesti päises näidatud tingimust kontrollima – kui tingimus kehtib ikka veel, siis täidetakse kehas olevad laused uuesti jne. Kui lõpuks tingimus enam ei kehti (antud näites peale 4 kordust), minnakse edasi while
-lausele järgnevate lausetega (antud juhul exitonclick()
).
Selleks, et taoline tsükkel ei jääks lõputult tööle, peab tsükli kehas olema midagi, mis mõjutab tingimuse kehtivust – antud näites on selleks lause joonistatud_kylgi = joonistatud_kylgi + 1
. Kuju poolest on siin tegemist täiesti tavalise omistuslausega, ainuke veider asi on see, et paremal pool mainitakse sedasama muutujat, mida parasjagu defineeritakse. Kas siin ei lähe miskit sõlme?
Muutuja muutmine¶
Pythoni muutujate süsteem on ehitatud selliselt, et muutuja väärtust on võimalik üle defineerida või lihtsamalt öeldes muuta. Iga muutuja viitab tegelikult ühele pesale või lahtrile kuskil Pythoni sisemuses olevas tabelis, ja selle lahtri sisu on võimalik omistuslausega muuta.
Antud näites genereerisime muutujale joonistatud_kylgi
uue väärtuse tema eelmise väärtuse põhjal. Selles pole Pythoni jaoks midagi erilist – nagu eelmises peatükis mainitud, väärtustab Python omistuslause käivitamisel kõigepealt parema poole ja salvestab saadud tulemuse vasakul pool näidatud muutujasse. Seega, kui joonistatud_kylgi
väärtuseks oli 0
, siis kõigepealt arvutati välja parema poole väärtus 1
ning alles seejärel uuendati muutuja sisu.
Tähelepanu!!!
Kui arvu- või sõneoperatsioonides (e tehetes) kasutada muutujaid (nt n + 1
või tekst.upper()
), siis võib avaldise kujust jääda mulje, et operatsiooni käigus muudetakse muutuja väärtust. Tegelikult genereeritakse tehte tulemusena hoopis uus väärtus ja kasutatud muutujaga midagi ei juhtu.
Selles veendumiseks uuri järgmisi käsurea näiteid, kus kõigepealt omistatakse muutujale mingi väärtus, seejärel kasutatakse muutujat mingis tehtes (mis konstrueerib uue väärtuse) ning lõpuks demonstreeritakse, et see ei mõjutanud muutuja väärtust:
>>> n = 3
>>> n + 2
5
>>> n
3
>>> sõna = ' kala '
>>> sõna.strip()
'kala'
>>> sõna
' kala '
>>> tekst = '3'
>>> int(tekst)
3
>>> tekst
'3'
Lühem kirjapilt muutuja kasvatamiseks / kahandamiseks¶
Muutuja väärtuse suurendamist mingi arvu võrra saab Pythonis ka lühemalt kirjutada: x = x + 1
asemel võime kirjutada x += 1
. Muutuja väärtuse vähendamiseks võib analoogselt kirjutada x -= 1
.
Terminoloogia
Muutujaid, mille väärtust suurendatakse igal tsükli sammul ühe võrra, nimetatakse loenduriteks. Selliseid tsükleid, kus korduste arv on tsükli alustamise hetkel teada, nimetatakse määratud tsükliteks.
Katsetus
Nagu mäletad, on +
defineeritud ka sõnede jaoks. Mida võiks +=
tähendada sõnede puhul?
Harjutus. Programm n-nurga joonistamiseks¶
Kirjuta ruudu näite põhjal programm, mis joonistab n-küljega hulknurga (n väärtus ja küljepikkus küsitakse kasutajalt).
Vihje
Iga nurga juures peab kilpkonn pöörama 360/n kraadi.
Näide. Tsükli ja tingimuslause kombineerimine¶
Nii if
-lause kui ka while
-lause keha võib koosneda suvalistest Pythoni lausetest. Järelikult võib panna ka if
-lause while
-lause sisse (ja vastupidi):
i = 1
while i <= 10:
print("Vaadeldav arv on", i)
if i % 2 == 0:
print("Tegemist on paarisarvuga")
else:
print("Tegemist on paaritu arvuga")
ruut = i * i
if ruut % 2 == 0:
print("Tema ruut", ruut, "on paarisarv")
else:
print("Tema ruut", ruut, "on paaritu arv")
print("--------------------------------")
i += 1
print("Sellega on meie arvuteoreetiline uurimus lõppenud")
Märkus
Eelmises peatükis soovitati valida muutujatele nimed, mis kirjeldavad nende tähendust. Selles näites on aga muutuja nimega i
, mis ei paista midagi tähendavat. Milles asi?
Asi on selles, et nime i
kasutamine tsüklimuutuja jaoks on lihtsalt väga levinud. Nähes muutujat nimega i
kusagil tsükli läheduses, eeldab iga vähegi kogenud programmeerija, et seda muutujat kasvatatakse igal tsükli sammul ühe võrra. Seega ei rikkunud me antud näites tähendusrikka muutujanime reeglit – sellele nimele lihtsalt ongi kujunenud oma tähendus.
Harjutus. Loendamine¶
Täienda eelnevat programmi veel ühe loenduriga, mille abil loetakse kokku 3-ga jaguvate ruutude arv. Kui kõik arvud on läbi vaadatud, siis väljasta saadud tulemus.
Määramata tsükkel¶
Alati pole võimalik ette öelda, mitu korda midagi kordama peab enne kui jõutakse soovitud tulemuseni. while
-lause sobib ka neil juhtudel, sest tsükli päises võime kasutada suvalist tingimust. Järgmine näiteprogramm laseb kasutajal arvata juhuslikult valitud arvu niikaua, kuni ta jõuab õige vastuseni:
from random import randint
arv = randint(1, 999) # randint annab juhusliku täisarvu näidatud vahemikust.
arvamus = int(input("Arva, millist tuhandest väiksemat arvu ma mõtlen: "))
# Kuni pakutud arv erineb arvuti valitust:
while arvamus != arv :
if arv > arvamus:
print("Minu arv on suurem!")
else:
print("Minu arv on väiksem!")
arvamus = int(input("Arva veelkord: "))
print("Ära arvasid! Tubli!")
Harjutus. Kolmeaastase lapse simulaator¶
Kirjuta programm, mis küsib kasutajalt mingi küsimuse ja seejärel küsib iga sisestuse peale „Aga miks?“ niikaua, kuni kasutaja sisestab mingi kindla „võlusõna“.
Harjutus. Algandmete kontrollimine tsükliga¶
Tsükleid saab kasutada algandmete sisestamise juures – me võime vigase sisendi puhul lasta kasutajal sisestamist korrata niikaua, kuni oleme sisestatud infoga rahul.
Kirjuta ruutjuure arvutamise programm, mis enne ruutjuure võtmist kontrollib, kas sisestati positiivne arv. Niikaua, kuni sisestati mittepositiivne arv, tuleb sisendi küsimist jätkata.
Lisavõimalus: käsk break
¶
Tsükli lõpetamise määrab tavaliselt tsükli päises olev tingimus. Sellele lisaks on Pythonis veel üks võimalus tsükli töö lõpetamiseks – selleks tuleb tsükli kehas anda sobival hetkel käsk break
.
Järgnevas näites on arvamismängu täiendatud selliselt, et ühte tsükli lõpetamise tingimust (arvu ära arvamine) kontrollitakse tsükli päises ning teist tingimust (10 ebaõnnestunud arvamist) kontrollitakse tsükli kehas:
from random import randint
arv = randint(1,999) # randint annab juhusliku täisarvu näidatud vahemikust.
arvamus = int(input("Arva, millist tuhandest väiksemat arvu ma mõtlen: "))
arvamise_kordi = 1
while arvamus != arv :
if arv > arvamus:
print("Minu arv on suurem!")
else:
print("Minu arv on väiksem!")
if arvamise_kordi == 10:
break
arvamus = int(input("Arva veelkord: "))
arvamise_kordi += 1 # lühem kirjapilt muutuja väärtuse suurendamiseks
# Kuna tsükkel võis lõppeda ka edutult, siis peame enne kiitmist kontrollima...
if arv == arvamus:
print("Ära arvasid! Tubli!")
else:
print("Kümnest arvamisest ei piisanud, äkki peaksid taktikat muutma?")
Tegelikult pole break
-lause Pythoni programmides hädavajalik - tsükli saab alati ümber kirjutada nii, et kõiki jätkamise/lõpetamise tingimusi kontrollitakse tsükli päises, aga vahel on break
-iga lahendus lihtsam.
Mõnikord on mugav tsükli lõpetamise tingimust kontrollida ainult tsükli kehas, sel juhul pannakse tsükli päisesse alati kehtiv tingimus True
. Järgnev programm küsib kasutajalt arve ja näitab nende ruute niikaua, kuni kasutaja sisestab tühisõne (st vajutab ENTER ilma midagi tegelikult sisestamata):
while True:
tekst = input("Sisesta arv ja vajuta ENTER (lõpetamiseks vajuta ainult ENTER): ")
if tekst == "":
print("OK, lõpetan")
break
else: # ei olnud tühisõne
arv = float(tekst)
print("Selle arvu ruut on", arv * arv)
Harjutus. Juhuslikud arvud¶
Kirjuta programm, mis väljastab iga ENTER-i vajutuse järel (st tühisõne sisestamisel) ekraanile juhusliku täisarvu vahemikus 1..999. Tsükli töö tuleks lõpetada (kasutades break
-i) siis, kui kasutaja sisestab tühisõne asemel sõne 'aitab'
.
Harjutus. Algandmete kontrollimine ja break
¶
Kui sa enne kasutasid algandmete kontrollimise ülesandes input
käsku mitmes kohas, siis proovi nüüd kirjutada lahendus ümber nii, et programmis on vaid üks input
käsk.
Näide. Summa arvutamine tsüklis¶
Senistes näidetes kasvatasime igal kordusel loenduri väärtust 1 võrra. Tegelikult ei ole Pythonil mingit põhjust piirata, kuidas me muutuja väärtust suurendame (või vähendame). Uuri ja proovi mõista järgmist näidet:
n = int(input("Sisesta naturaalarv: "))
summa = 0
i = 0
while i <= n:
summa += i
i += 2
print(n, "esimese naturaalarvu hulgas olevate paarisarvude summa on", summa)
Antud juhul suurendasime igal tsükli kordusel muutuja i
väärtust 2 võrra ja muutuja summa
väärtust teise muutuja (i
) hetkeväärtuse võrra.
Harjutus. Faktoriaali arvutamine¶
Kirjuta programm, mis arvutab etteantud arvu faktoriaali.
Märkus
Kuidas käitub sinu programm negatiivse arvu korral?
Näide. Kahekordne tsükkel¶
Nii nagu me võime while
-lause kehas kasutada if
-lauseid, võime seal kasutada ka while
-lauseid. Järgnev programm kasutab kahekordset tsüklit korrutustabeli kuvamiseks:
# välimine tsükkel teeb ühe korduse iga rea jaoks
rea_nr = 1
while rea_nr < 10:
# sisemine tsükkel genereerib arvud käesolevasse ritta
veeru_nr = 1 # iga uue rea puhul alustame jälle veerust nr. 1
while veeru_nr < 10:
korrutis = rea_nr * veeru_nr
print(str(korrutis) + " ", end="") # end="" abil väldime väljundisse reavahetuse panemist
# suurendame veeru numbrit
veeru_nr += 1
# reavahetuse paneme alles siis, kui kõik käesoleva rea numbrid on väljastatud
print()
# suurendame rea numbrit
rea_nr += 1
Märkus
Ära muretse, kui see programm tundub hetkel liiga keeruline! Mitmekordsete tsüklitega hakkame tõsisemalt tegelema alles mitme peatüki pärast. Praegu on oluline vaid meelde jätta, et Python ei sea kitsendusi sellele, mida võib while
või if
-lause sisse panna.
Harjutus. Korrutustabeli korrastamine¶
Eelmise näiteprogrammi väljund jäi natuke kipakaks, sest osad korrutised olid ühekohalised, osad kahekohalised ja seetõttu ei jäänud veerud kohakuti. Täienda nüüd programmi nii, et see väljastaks umbes taolise tabeli:
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81
Vihje
Üks võimalus on teatud tingimusel printida korrutise ette üks lisatühik.
Vihje
Teine võimalus on kasutada ühte sõneoperatsiooni, mille kohta on näide ühes 2. peatüki tabelis.
Näide. Failist lugemine tsükliga¶
Meie senised ridahaaval failist lugemise näiteprogrammid teadsid (õigemini eeldasid), mitu rida antud failis on. Praktikas tuleb aga palju sagedamini ette situatsioone, kus faili ridade arv pole teada. Järgnev näide demonstreerib faili kõikide ridade lugemist:
f = open('nimed.txt')
while True:
nimi = f.readline()
# kui jõuti faili lõppu, siis readline tagastab tühja sõne
if nimi == "":
break
if nimi.strip() == 'Margus': # strip eemaldab reavahetuse sümboli
print('Hommik!')
print('Kuis kulgeb?')
else:
print('Tervist, lugupeetud ' + nimi.strip() + '!')
f.close()
Veaotsingu nipp
Selles näites kasutasime strip
meetodit seepärast, et failist ridade lugemisel jäetakse rea lõppu ka reavahetuse sümbol. Selline nüanss aga ei pruugi alati meelde tulla ja sel juhul programm lihtsalt ei tööta õigesti.
Kui tekib selline situatsioon, kus programm ei tööta nii nagu sa soovid, siis võiks kõigepealt uurida, kas sisendandmed loeti sisse selliselt nagu sa arvasid. Antud programmis võiks tsüklis esimese asjana peale rea sisselugemist kuvada selle ekraanile. Selleks, et oleks näha ka tühikute ning reavahetuste paiknemine, võib kuvamist teha nt selliselt: print('>' + nimi + '<')
.
Harjutus. Failis olevate temperatuuride teisendamine¶
Kirjuta programm, mis loeb tekstifailist temperatuure Fahrenheiti skaalas ja väljastab ekraanile vastavad temperatuurid Celsiuse skaalas.
Vihje
Ära unusta, et readline
tagastab sõne. Arvutamiseks on vaja see teisendada arvuks.
Tõeväärtustüüp bool
¶
Nagu varem mainitud, koosneb iga Pythoni programm lausetest ja lause komponendid on avaldised. Tuleb välja, et Python peab ka if
või while
-lause päises olevat tingimust avaldiseks. Aga kui igal avaldisel on väärtus, siis millised näevad välja tingimuse väärtused? Proovime järele:
>>> 3 > 2
True
>>> 3 > 3
False
>>> 3 >= 3
True
>>> x = 4
>>> y = 5
>>> x == y
False
>>> y > x
True
>>> toit = "kapsas" # NB! ühe võrdusmärgiga on omistamine
>>> toit == "kapsas" # kahe võrdusmärgiga on võrdsuse kontrollimine
True
Selgitus: tingimuste jaoks on Pythonis eraldi andmetüüp nimega bool
, milles on vaid kaks võimalikku väärtust – True
ja False
. Eesti keeles nimetatakse seda andmetüüpi tõeväärtustüübiks (bool
on lühend sõnast boolean
, mis tuleb omakorda matemaatiku George Boole’i nimest).
Pole kokkusattumus, et me käsitleme seda andmetüüpi just tingimuslausete peatükis – kõik avaldised, mis annavad väärtustamisel tulemuseks True
või False
, sobivad if
või while
-lause päisesse ning nende lausete päised on põhiline koht, kus tõeväärtusi kohtab.
Märkus
Nagu iga avaldise puhul, saab ka tõeväärtusavaldise põhjal defineerida muutujaid. Kuna if
-lause päises võib tõeväärtus olla antud mistahes kujul, siis võiksime mingi kontrolli tulemuse salvestada eelnevalt muutujasse ning hiljem kasutada seda muutujat tingimusena:
arv = int(input("Sisesta arv: "))
jagub_kahega = arv % 2 == 0 # salvestame tõeväärtuse abimuutujasse
if jagub_kahega:
print("Sisestati paarisarv")
else:
print("Sisestati paaritu arv")
Antud näites ei andnud abimuutuja kasutamine küll midagi juurde – samaväärse programmi võiksime panna kirja ka lihtsamalt:
arv = int(input("Sisesta arv: "))
if arv % 2 == 0:
print("Sisestati paarisarv")
else:
print("Sisestati paaritu arv")
Keerulisemate tingimuste korral võib aga abimuutuja kasutamine teha koodi paremini loetavaks.
Tõeväärtustehted¶
Kuigi tõeväärtustüübis on vaid kaks väärtust True
ja False
, on olemas palju erinevaid viise nende genereerimiseks. Järgnev tabel demonstreerib mõnesid neist:
Avaldis | Väärtus | Selgitus |
---|---|---|
2 == 2.0 |
True |
== sobib nii sõnede kui ka arvude võrdsuse kontrollimiseks |
'tere' == 'tere' |
True |
|
'TeRe' == 'tere' |
False |
Sõnede võrdlemisel tehakse suur- ja väiketähtedel vahet |
2 == '2' |
False |
Ükski sõne pole ühegi arvuga võrdne |
2 != '2' |
True |
Mittevõrdsuse kontroll – != annab True neil juhtudel,
kus == annaks False ja vastupidi |
2 != 2 |
False |
|
3 > 3 |
False |
Arvude võrdlemine toimub ootuspäraselt |
3 >= 3 |
True |
|
2 < 3 |
True |
|
2 <= 3 |
True |
|
'kana' > 'kalkun' |
True |
Sõnede võrdlemine toimub tähestiku järgi |
'r' in 'tore' |
True |
in kontrollib tähe või alamsõne leidumist sõnes |
'r' in 'tobe' |
False |
|
'art' in 'Tartu' |
True |
|
'Tallinn'.endswith('linn') |
True |
Sõnemeetodid startswith ja endswith teevad seda, mida võiks
nende nimedest arvata |
'Tallinn'.startswith('reha') |
False |
|
'10203'.isnumeric() |
True |
isnumeric annab True , kui sõne sisaldab ainult numbreid |
Loomulikult saab kõiki mainitud operatsioone kasutada ka muutujatega.
Harjutus. Mitte-tõstutundlik sõnede võrdlemine¶
Mitte-tõstutundlik võrdlemine tähendab seda, et suur- ja väiketähtedel ei tehta vahet. Sellise võrdlemise korral loetakse sõned "TeRe"
ja "tere"
võrdseks. Pythonis selle jaoks eraldi konstruktsiooni pole, aga seda saab erinevaid operatsioone kombineerides siiski teha.
Kirjuta avaldis, mis võrdleb kahte muutujatena antud sõne a
ja b
ning mille tulemuseks oleks True
parajasti siis, kui vastavad sõned on võrdsed ilma suur- ja väiketähtedel vahet tegemata.
Vihje
upper
Vihje
… või lower
Vihje
>>> "tere".upper()
'TERE'
>>> "TERE".upper()
'TERE'
Vihje
>>> a = "TeRe"
>>> b = "tere"
>>> a == b
False
>>> a.upper() == b
False
>>> a.upper() == b.upper()
True
>>> a.lower() == b.lower()
True
Harjutus. Arvu ruut koos kontrolliga¶
Kirjuta programm, mis küsib kasutajalt positiivse täisarvu ning väljastab selle arvu ruudu. Kui sisestatud tekst ei ole numbriline, siis kuvatakse vastavasisuline veateade.
Tõeväärtuste kombineerimine¶
Nägime, et tõeväärtused on paljude arvu- ja sõnetehete tulemuseks. Kas on olemas mingeid mõistlikke tehteid, mida saab teha tõeväärtuste endiga?
Kõige tähtsamad tehted, mille argumendid on tõeväärtused, s.o loogilised tehted, on and
, or
ja not
. Nende operaatorite tähendus on arvatavasti intuitiivselt arusaadav, kuid vajadusel saab kõik kombinatsioonid Pythoni käsureal järele proovida.
True and True
True and False
False and True
False and False
True or True
True or False
False or True
False or False
not True
not False
Loomulikult ei hakka keegi kirjutama programmi, mis arvutaks välja avaldise True and False
väärtuse – loogilisi tehteid kasutatakse tavaliselt teiste tõeväärtusavaldiste kombineerimiseks, nii nagu järgmises kahes näites:
parool = input("Sisesta oma uus parool: ")
if len(parool) >= 8 and parool != "password":
print("Hea valik!")
else:
print("See parool jääb lahjaks!")
kuu = int(input("Sisesta kuu number: "))
if kuu == 1 or kuu == 3 or kuu == 5 or kuu == 7 or kuu = 8 or kuu == 10 or kuu == 12:
print("Selles kuus on 31 päeva")
else:
print("Selles kuus on vähem kui 31 päeva")
Tehete järjekord¶
Keerulisemate loogiliste avaldiste puhul tuleb arvestada, et not
on kõrgema prioriteediga kui and
ning and
on kõrgema prioriteediga kui or
, seega not x or not y and z
tähendab (not x) or ((not y) and z)
.
Kuna ühes avaldises võivad olla koos aritmeetilised tehted, võrdlustehted ja loogilised tehted, siis selleks, et vähendada sulgude vajadust, on aritmeetilised tehted kõrgema prioriteediga (st tehakse esimesena) ning loogilised tehted on madalama prioriteediga (tehakse viimasena), seega a > b and b > c
tähendab (a > b) and (b > c)
.
Harjutus. Samaväärne loogiline avaldis¶
Kirjuta järgneva avaldisega samaväärne avaldis, milles poleks kasutatud not
tehet:
not (x < 0 and x > 100)
Pykkar¶
Nagu eespool veendusime, saab robotkilpkonna juhtimisel tsüklitega teha päris keerulisi asju. Nüüd tutvustame aga järgmist programmeeritavat tegelast, kes lisaks käskude vastuvõtmisele annab ka infot teda ümbritseva keskkonna kohta. Saage tuttavaks, Pykkar!
Pykkar on virtuaalne robot, kes tegutseb oma virtuaalses maailmas. Ta oskab liikuda, värvida, asju kanda ja tal on ka sensorid, mis suudavad näiteks anda märku kui otse ees asub sein. See omadus sobib antud peatükki oivaliselt, sest sensoritelt saadud info ning if
- ja while
-lausete abil saame panna Pykkari tegevuse sõltuma konkreetsest situatsioonist.
Esimese näitena laseme Pykkaril liikuda otse edasi, kuni ta jõuab seinani ning siis ümber pöörata. See programm (nagu ka kõik meie järgnevad Pykkari programmid) vajab oma tööks moodulit pykkar
(failis pykkar.py
), mis ei kuulu Pythoni standardteeki ja tuleb seega enne näiteprogrammi käivitamist salvestada enda arvutisse, näiteprogrammiga samasse kausta.
Märkus
Alternatiivina ava Thonnys menüü Tools => Open system shell ja sisesta pip install pykkar
.
from pykkar import *
# create_world võtab argumendiks mitmerealise sõne, mis esitab roboti maailma.
# Trellid tähistavad seinu, nooleke tähistab robotit.
# Noole suund (>, <, v või ^) tähistab roboti suunda.
create_world("""
########
# > #
# #
# #
# #
# #
########
""")
# liigu seinani
while not is_wall(): # is_wall() annab True, kui Pykkar on ninaga vastu seina
step()
# pööra ringi
right()
right()
Loodetavasti nägid programmi käivitamisel umbes sellist pilti, millele järgnes roboti liikumise animatsioon:
Harjutus. Maksimaalselt 4 sammu¶
Muuda eelmist näidet selliselt, et Pykkar üritab kõndida 4 sammu, aga kui sein tuleb varem vastu, siis jääb ta seisma seina ääres. Lõpuks pöörab ta ennast ümber.
Programm peab töötama suvalise maailma ja suvalise Pykkari alguspositsiooni korral.
Vihje
Üks võimalik lahendus:
from pykkar import *
create_world("""
########
# > #
# #
# #
# #
# #
########
""")
samme_jäänud = 4
while samme_jäänud > 0:
if is_wall():
break
else:
step()
samme_jäänud -= 1
# pöörame ringi
right()
right()
Pykkari maailm ja käsud¶
Vaatame nüüd üle, millises maailmas Pykkar tegutseb ja milliseid käske ta tunneb.
Maailm luuakse käsuga create_world
, mille argument on mitmerealine sõne, mis esitab maailma kaarti, kus iga sümbol tähistab ühte ruutu. Järgnev tabel võtab kokku, milliseid ruute on võimalik kasutada:
Ruudu sümbol | Tähendus | Näide |
---|---|---|
(tühik) | Hele põrand | |
. |
Tume põrand | |
# |
Sein | |
^ , > , v , < |
Pykkar heledal põrandal, nool näitab suunda | |
N , E , S , W |
Pykkar tumedal põrandal, ilmakaare täht näitab suunda | |
1 , 2 , …, 9 |
Vastav arv liiklustorbikuid heledal põrandal | |
C |
Üks liiklustorbik tumedal põrandal | |
b |
Kast heledal põrandal | |
B |
Kast tumedal põrandal |
NB! Maailmas on ruumi vaid ühele Pykkarile, st kaardile võib valida ^
, >
, v
, <
, N
, E
, S
, W
hulgast vaid ühe sümboli.
Pykkar saab aru järgnevatest käskudest:
Käsk | Tähendus |
---|---|
step() |
Liigu üks samm edasi |
right() |
Pööra 90° paremale |
take() |
Korja üles üks järgmisel ruudul olev torbik. Pykkar suudab transportida ühte torbikut korraga |
put() |
Pane ülesvõetud torbik maha järgmisele ruudule (seal võib olla juba kuni 8 torbikut ees) |
push() |
Lükka järgmisel ruudul olevat kasti või torbikut |
paint() |
Värvi enda all olev ruut tumedaks |
is_wall() |
Ütle, kas ees on sein (vastab True või False ) |
is_cone() |
Ütle, kas ees on torbik |
is_box() |
Ütle, kas ees on kast |
is_painted() |
Ütle, kas enda all olev ruut on tume |
get_direction() |
Ütle, millisesse suunda oled hetkel pööratud (vastab 'N' , 'E' , 'S' või 'W' ) |
Pykkar ei oska tõepoolest vasakule pöörata! Õnneks on võimalik sama efekt siiski saavutada. Kuidas?
Harjutus. Torbiku kandmine¶
Kirjuta programm, mis loob allolevale pildile vastava maailma:
Lisa Pykkari käsud, mis muudavad maailma seisu selliseks:
NB! Programm peab töötama ka laiemate ja kitsamate maailmade korral.
Erindite püüdmine try
-lausega¶
Vaatame ühte lühikest ja lihtsat programmi:
arv1 = float(input("Sisesta esimene arv: "))
arv2 = float(input("Sisesta teine arv: "))
print("Nende arvude jagatis on", arv1 / arv2)
Mis juhtub siis, kui kasutaja sisestab ühe soovitud arvu (nt. 45
) asemel kogemata midagi, millest Python ei oska arvu välja lugeda (näiteks 45t
)? Proovi järele!
Ilmselt nägid, et Python väljastas ekraanile veateate, ning lõpetas programmi töö. Selle programmi puhul polnud see suur õnnetus, aga keerulisemates programmides, kus kasutaja on suure ülesandega poole peale jõudnud, oleks üpris kahju kui selline väike aps programmi sulgeks. Seetõttu on Pythonisse loodud võimalused täitmisaegsete vigade e erindite „püüdmiseks“.
Vigade püüdimiseks tuleb kasutada try
-lauset. Alustame näitest:
try:
arv1 = float(input("Sisesta esimene arv: "))
arv2 = float(input("Sisesta teine arv: "))
print("Nende arvude jagatis on", arv1 / arv2)
except:
print("Hmm..., midagi läks vussi.")
Nii nagu if
-else
-lause, koosneb ka try
-lause mitmest osast – võtmesõna try
alla kirjutatakse laused, mida soovitakse normaalsel juhul täita ning võtmesõna except
alla laused, mida täidetakse siis, kui try
-osa lausete täitmisel tekib mingi viga (siit ka võtmesõna except
– neid lauseid soovime täita vaid erandjuhtumitel).
Antud näite puhul on küsitav, kuivõrd try
-lause lisamine midagi paremaks tegi – me küll peitsime kasutaja eest ära koleda mitmerealise veateate (kas see peitmine oli üldse hea?), aga vigase sisestuse korral jäi kasutaja ikkagi vastusest ilma. Koodi kavalalt ümber paigutades saame me aga programmi, mis küsib kasutajalt arve niikaua, kuni lõpuks teisendamine ja jagamine õnnestub:
while True:
try:
arv1 = float(input("Sisesta esimene arv: "))
arv2 = float(input("Sisesta teine arv: "))
print("Nende arvude jagatis on", arv1 / arv2)
break
except:
print("Hmm..., midagi läks vussi.")
print("Proovime uuesti!")
Siin me panime kogu programmi loogika tsüklisse, millest pääseb välja käsuga break
. Selle käsuni jõuab Python aga ainult siis, kui kõik try
-osa laused edukalt läbitakse – niipea, kui kusagil eespool tekib mingi viga, hüpatakse kohe except
-osasse ning peale selle täitmist jätkatakse uuesti tsükli algusest.
Hoiatus
Vigade kinnipüüdmine on põhjendatud ainult siis, kui sa tõesti oskad selle veasituatsiooniga midagi ette võtta. Vigu ei tohiks püüda kinni lihtsalt selleks, et vältida veateate ekraanile jõudmist – see võib tekitada situatsiooni, kus programmis on mingi probleem, aga ei programmeerija ega kasutaja ei saa sellest teada ning programm annab süüdimatult välja valed tulemused.
Harjutus. Peenem vigade püüdmine¶
Viimase näite puhul, kui probleem oli teises arvus, pidi kasutaja sisestama uuesti ka esimese arvu. Kirjuta programm nüüd ümber selliselt, et kui esimene sisestatud arv teisendamine õnnestus, siis seda enam uuesti ei küsita.
Vihje
Jaga programm kaheks osaks …
Vihje
… kumbki oma while
-tsüklis, oma try
-ga .
Vihje
Näidislahendus:
while True:
try:
arv1 = float(input("Sisesta esimene arv: "))
break
except:
print("Hmm..., midagi läks vussi.")
print("Proovime uuesti!")
while True:
try:
arv2 = float(input("Sisesta teine arv: "))
print("Nende arvude jagatis on", arv1 / arv2)
break
except:
print("Hmm..., midagi läks vussi.")
print("Proovime uuesti!")
Kokkuvõte¶
Selles peatükis nägime, et Pythoni programm ei pruugi olla vaid lihtsate käskude jada, mida täidetakse üksteise järel, kuni jõutakse programmi lõppu. Vaatlesime kahte programmikonstruktsiooni, millel kõigil on päis ja tühikutega veidi paremale nihutatud keha, kusjuures kehas olevate lausete täitmise viis on mõlemal juhul erinev.
- Tingimuslause e
if
-lause peaharus olevad laused täidetakse ainult siis, kui päises esitatud tingimus kehtib. Kui tingimuslauses on olemas kaelse
haru, siis seal olevad laused täidetakse siis, kui tingimus ei kehti. Sellise konstruktsiooniga saab muuta programme paindlikumaks, pannes need käituma üht- või teistmoodi vastavalt olukorrale. - Korduslause e tsükli puhul täidetakse kehas olevad laused 0 või rohkem korda, vastavalt päisele. Sarnaselt tingimuslausega, kontrollitakse selles peatükis vaadeldud
while
-lause korral enne kehas olevate lausete täitmist, kas päises antud tingimus kehtib. Erinevalt tingimuslausest minnakse peale keha täitmist uuesti tingimust kontrollima ja kui see kehtib endiselt, siis täidetakse kehas olevad laused uuesti jne. Seda protsessi korratakse niikaua, kuni tingimus enam ei kehti. Korduslausega saame kirjeldada protsesse, kus sama toimingut tuleb teha mitu korda järjest (ja seejuures ei pruugi me korduste arvu programmi kirjutamisel ette teada). - Erindite püüdmine käib
try
-lausega, mis võimaldabexcept
-osas näidata laused, mida täidetakse siis, kui mõnitry
-osa lausetest ebaõnnestub.
Kõiki vaadeldavaid programmikonstruktsioone nimetatakse Pythonis liitlauseteks, kuna nende kehad koosnevad teistest (suvalist liiki) lausetest. See võimaldab näiteks tingimuslause kehas lisaks lihtlausetele kasutada ka korduslauset, mille kehas on omakorda kasutatud tingmuslauset, mille kehas on veel üks tingimuslause jne.
Taolist lausete üksteise sisse panemist esitatakse Pythonis treppimisega – samasse kehasse (e plokki) kuuluvate lausete vasakud servad joondatakse tühikute abil sama kaugele. Liitlausete puhul joondatakse eelnevate ja järgnevate lausetega vaadeldava lause päis, keha (if ... else
puhul mõlemad harud) nihutatakse päisega võrreldes veel rohkem paremale.
Ülesanded¶
1. Paaris või paaritu¶
Koosta tekstifail, mis sisaldab täisarve erinevatel ridadel. Kirjuta programm, mis loeb antud failist ükshaaval arve ning kuvab iga arvu kohta ekraanile info, kas tegemist oli paaris või paaritu arvuga. Programm peab töötama suvalise ridade arvu korral.
2. Pere sissetulek¶
Kirjuta programm, 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 50€ kuus.)
Esialgu võid eeldada, et mõlema vanema kuupalk on vähemalt sama suur kui maksuvaba miinimum. (Siiamaani saaksid selle ülesande lahendada ka ilma selle peatüki vahenditeta.)
Lõpuks korralda nii, et programm töötab õigesti ka siis, kui ema või isa brutopalk on maksuvabast miinimumist väiksem.
3. Busside logistika¶
Olgu meil vaja transportida teatud arv inimesi bussidega, milles on teatud arv kohti. Mitu bussi on vaja selleks, et kõik inimesed kohale saaksid, ja mitu inimest on viimases bussis (eeldusel, et eelmised on kõik täiesti täis)? Kirjuta programm, mis küsib inimeste arvu ja busside suuruse ning lahendab seejärel selle ülesande.
Testi oma programmi muuhulgas järgmiste algandmetega:
- inimeste arv: 60, kohtade arv: 40;
- inimeste arv: 80, kohtade arv: 40;
- inimeste arv: 20, kohtade arv: 40;
- inimeste arv: 40, kohtade arv: 40.
Ürita mõista, miks valiti taolised testiandmed.
Küsimus
Kas seda ülesannet saab lahendada ka ilma if
-lauset kasutamata? Kui jah, siis kuidas?
4. Liigu nurka¶
Kirjuta Pykkari programm, mis suvalise ristkülikukujulise maailma puhul liigutab Pykkari kirdenurka (NE). Programm võib eeldada, et robot vaatab alguses lõunasse, aga tema algne asukoht võib olla suvaline. Programmi lõpuks peab Pykkar olema näoga põhjasuunas.
Katseta programmi näiteks selliste algseisudega:
########
# #
# #
# v #
# #
# #
########
ja
##########
# #
# #
# #
# v #
##########
Kas su programm töötab õigesti ka siis, kui Pykkar juba on kirdenurgas?
Väljakutse
Muuda programmi nii, et ka roboti algse suuna kohta ei eeldata midagi.
5. projecteuler.net, problem 1¶
Kirjuta programm, mis lahendab esimese ülesande aadressilt http://projecteuler.net/problems.
Märkus
Soovitame otsida sellelt saidilt endale huvipakkuvaid ülesandeid ka edaspidi! Kui teed endale seal konto, siis saad oma progressi salvestada ja tulemusi kontrollida.
6. Ringi joonistamine¶
Kirjuta programm, mis joonistab kilpkonnaga pisikestest sirglõikudest koosneva ringitaolise kujundi. Ringi suurus pole praegu oluline.
Vihje
Sarnane ülesanne on ülalpool juba antud, aga natuke teises sõnastuses.
7. Kolmnurk¶
Kirjuta programm, mis küsib kasutajalt ridade arvu ning väljastab ekraanile vastava kõrgusega kolmnurga:
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
Vihje
Tuleta meelde, mida tähendab 'Tere' * 4
.
8. Horisontaalsed tulbad¶
Kirjuta programm, mis kuvaks failis olevate arvude põhjal tekstilisi, horisontaalsete tulpadega tulpdiagramme. Näiteks kui faili sisu on
3
2
13
6
9
4
7
siis ekraanile peaks ilmuma
* * *
* *
* * * * * * * * * * * * *
* * * * * *
* * * * * * * * *
* * * *
* * * * * * *
9. Kivi-paber-käärid¶
Kirjuta programm, mis väljastab iga ENTER-klahvi vajutuse peale ühe juhuslikult valitud sõna loetelust „kivi“, „paber“, „käärid“. Programmi töö lõpetamiseks tuleb kasutajal enne ENTER-i vajutamist sisestada „aitab“.
Vihje
ENTER-i vajutamine on Pythoni jaoks sama, mis tühja sõne sisestamine
Vihje
>>> from random import randint
>>> randint(1,3)
3
>>> randint(1,3)
1
10. Erindite püüdmine failist lugemisel¶
Kirjuta programm, mis loeb tekstifailist temperatuure Celsiuse skaalal ja kuvab neid ekraanile Fahrenheiti skaalal. Faili nende ridade juures, kus arvuks teisendamine miskipärast ebaõnnestub, tuleb ekraanile kuvada „Vigane sisend“, ning jätkata faili järgmise reaga.
Vihje
...
while ...:
...
... readline()
...
try:
...
... float(...)
...
except:
...
11. Pentagramm vol 2¶
Kui lahendasid eelmises peatükis pentagrammi ülesande, siis proovi nüüd oma programmi tsükli abil lühemaks teha.
12. Spiraalid¶
Joonista kilpkonnaga allolevad spiraalid. Proovi kujundada veel mingi teistmoodi spiraal.
Vihje
Viimased 2 spiraali on koostatud väikestest sirglõikudest.
13. Raskem: Risttahukas¶
Kirjuta programm, mis kuvab ekraanile erinevatest kriipsutaolistest sümbolitest moodustatud kasti, mille külgede mõõtmed annab ette programmi kasutaja. Näiteks mõõtmetega 5x3x2 näeks kast välja selline:
___________
/ /\
/ / \
/__________/ /
\ \ /
\__________\/
14. Raskem: Redeli asendid¶
Genereeri Pythoni kilpkonnaga joonistus, mis kujutab redelit (esitatud lihtsalt sirgjoonena) seina najal erinevate nurkade all. Joonista redel kõigepealt horisontaalasendis ning seejärel mitmes asendis järjest suurema nurga all, kuni lõpuks jõuab redel vertikaalasendisse.
Vihje
Abiks võib olla turtle
’i käsk back
, mis liigutab kilpkonna senise suunaga võrreldes tagurpidi. (Aga see pole ülesande lahendamiseks tingimata vajalik.)
15. Raskem: Ruudustik¶
Kirjuta programm, mis küsib ruutude arvu vertikaalsuunal, ruutude arvu horisontaalsuunal ning joonistab kilpkonna abil vastava ruudustiku, nt:
Lisaülesande lisa
Uuri kilpkonna dokumentatsioonist, kuidas värvida soovitud ala (http://docs.python.org/3/library/turtle.html). Seejärel proovi joonistada malelaud.
Praktilisi näpunäiteid¶
Veaotsingust¶
Esimeses peatükis sai juba veidi tutvustatud Pythoni veateadete hingeelu. (Kuna nüüd oled veateateid juba rohkem näinud, on soovitatav see osa uuesti, uue pilguga üle lugeda.)
Nagu ilmselt juba oled kogenud, on kõige problemaatilisemad vead aga need, mille kohta Python veateadet ei taipa anda. Selleks, et taolisi vigu väiksema närvikuluga avastada, soovitame lugeda läbi lihtsad ja kasulikud retseptid järgnevalt aadressilt: http://openbookproject.net/thinkcs/python/english3e/app_a.html.
Lisalugemine¶
Matemaatika ja programmeerimine
Loodetavasti veendud järgnevat lugedes, et matemaatikat ja programmeerimist (ning matemaatika ja programmeerimise õppimist) saab omavahel väga edukalt siduda. Tegelikult ongi väga kasulik mingi uue matemaatilise mõiste õppimisel proovida väljendada seda mõnes programmeerimiskeeles. Erinevalt tavakeelest peab programmeerimiskeeles väljendama ennast alati absoluutselt täpselt, seetõttu toob taoline harjutus välja need aspektid, mille osas sinu arusaamine antud mõistest on jäänud veidi hägusaks.
Ruutjuure leidmine¶
Kuidas arvutada ruutjuurt? Kui importida moodul math
, on asi muidugi lihtne. Tegelikult ei vasta see aga küsimusele, vaid lükkab selle lihtsalt meist kaugemale – me teame, et seda funktsiooni välja kutsudes saame õige tulemuse, kuid me ei tea, kuidas arvuti selleni jõuab. Järgnevalt vaatame ühte viisi ruutjuure leidmiseks, kus kasutatakse vaid lihtsaid aritmeetilisi tehteid.
Olgu meil antud arv y. Otsime sellist x et x * x = y. Siis aga x = y / x. Seega, kui võtta mingi lähend x0 selle ruutjuure jaoks, võiks x0 ja y/x0 aritmeetiline keskmine olla tegelikule ruutjuure väärtusele juba lähemal, kui x0 ise seda on. Tuleb välja, et nii enamasti ka on. See lubab ruutjuure leidmiseks kirjutada järgmise programmi:
y = float(input("Sisesta arv, mille ruutjuurt tahad leida: "))
x0 = 1
while True :
eelmine_x0 = x0
x0 = (x0 + y / x0 ) / 2.0
print("Lähend on " + str(x0))
# Lõpeta arvutamine, kui lähend enam eriti ei muutu.
if abs(x0-eelmine_x0) < 0.0000001:
break
print("Ruutjuur on ligikaudu: " + str(x0))
while True
tähendab lõpmatut kordust. Tsükli kehas on aga siiski if
-lause, mille tingimuse täidetuse korral kordus break-käsuga lõpetatakse. if
-lause kontrollib sisuliselt seda, kas eelmise lähendi ja uue lähendi erinevus on väiksem kui 0,0000001. Peale natukest katsetamist peaks olema selge, et enamasti jõutakse sellise täpsuseni väga väheste korduste arvuga. Võiksid kontrollimise huvides võrrelda selle programmi ja näiteks math.sqrt
tulemusi. Sellist lähendi leidmise meetodit nimetatakse Newtoni iteratsioonimeetodiks inglise matemaatiku ja füüsiku Isaac Newtoni auks.
Katsetamise teel arvutamine
Ruutjuure leidmise ülesande võiksime panna kirja ka võrrandina, nt x² = 762. Nagu eelnevast selgus, saame arvuti abil lahendada taolise võrrandi ka lihtsalt proovides x asemele erinevaid väärtusi. Kas sellise taktikaga saaks lahendada suvalisi võrrandeid?
π leidmine¶
Järgmisena kirjeldame aga omapärast viisi π (ringi ümbermõõdu ja diameetri vahelise suhte) väärtuse leidmiseks. Kui joonistada ruut ja selle sisse ring, siis kui ringi raadius on r, on ruudu pindala (2*r)*(2*r) = 4*r**2 ja ringi pindala pi*r**2. Seega ringi pindala moodustab pi/4 kogu ruudu pindalast. Seega, valides juhusliku punkti ruudu seest, asub ta ringi sees tõenäosusega pi/4. Niisiis kui valida juhuslikult palju punkte ruudu seest, peaks ligikaudu pi/4 osa neist olema ringi sees. Neid kokku lugedes saame seega hinnata pi/4 väärtust suhtega ringi sees olevate arv / katsete koguarv.
Teame, et ringi moodustavad kõik punktid, mis on tema keskpunktile lähemal kui raadius. Seega, kui keskpunkt on (0,0), siis on ringi sees täpselt need punktid (x,y), mille korral sqrt(x**2 + y**2) ≤ r, st. x**2 + y**2 ≤ r**2. Valides r=1, saame koostada järgmise programmi:
import random
n = int(input("Sisesta katsete arv: "))
c = 0
i = 0
while i < n:
# Genereeri juhuslik punkt.
x = random.uniform(-1,1)
y = random.uniform(-1,1)
# Kontrolli, kas ta on ringi sees.
if (x**2 + y**2 < 1):
c=c+1
i += 1
print("Hinnang on "+ str((4.0*c) / n))
Funktsioon random.uniform
valib ühtlase jaotuse põhjal juhuslikult ühe reaalarvu etteantud vahemikust. Kõik muu programmi juures peaks olema juba tuttav.
Katsetamine erinevate katsete arvudega (10,100,1000,…,1000000) peaks veenma, et kuigi tulemused on reeglina π-le lähedased, on see siiski suhteliselt halb meetod π kohtade leidmiseks, sest vähegi mõistliku täpsuse saamiseks tuleb teha väga palju katseid.
Graafiline versioon
Kui selle lahenduskäigu põhimõte jäi hägusaks, siis lae alla järgnev programm, mis demonstreerib sama asja graafiliselt: pi_demo.py
. Juhuslike täppide genereerimiseks tee programmi aknas hiireklõpse (hiirekursori asukoht pole tähtis). Iga uue täpi lisandumisel korrigeeritakse arvutatud pi väärtust vastavalt sellele, kas täpp sattus ringi sisse või mitte. Jooksvat tulemust näidatakse käsurea aknas.
Selliseid arvutusmeetodeid nimetatakse Monte Carlo meetoditeks (kuulsa kasiinolinna järgi Monacos). Antud näide on taas pigem illustratiivne – praktikas kasutatakse seda reeglina ülesannete puhul, mida muud moodi lahendada ei osata. π arvutamiseks teatakse aga palju teisi ja oluliselt paremaid meetodeid.