Ehdot silmukoissa
Osallistu tutkimukseen - vastaa kyselyyn
Alla olevan linkin takaa löytyy Hannu Pesosen väitöskirjatutkimukseen liittyvä kysely. Kurssin suorittaminen ei edellytä kyselyyn vastaamista, mutta yliopistoissa tutkimus on luonnollisesti tärkeässä osassa myös opetuksen kehittämisessä.
Jos sinulta siis löytyy hetki aikaa, niin vastaa kyselyyn.
Kyselyyn ei ole pakko antaa henkilötietoja (esimerkiksi nimeä), vaikka niitä ensimmäisellä sivulla kysytäänkin.
Edellisen osan lopussa opimme käyttämään while True
-silmukkaa koodin toistamiseen. Tässä tapauksessa silmukan ehtona on True
, joka on aina tosi. Esimerkiksi
# Tulosta lukuja kunnes muuttujan a arvo on 5
a = 1
while True:
print(a)
a += 1
if a == 5:
break
1 2 3 4
Silmukan toimintaa voidaan monipuolistaa käyttämällä ehtoa while
-määrittelyssä. Yleisemmin voimme siis käyttää silmukkaa näin:
while <ehtolauseke>:
<lohko>
Ideana on, että silmukka vuorotellen tarkastaa ehdon ja suorittaa lohkossa olevan koodin, jos ehto on tosi. Sitten kun ehto on epätosi, ohjelman suoritus jatkuu silmukan jälkeiseltä riviltä.
Esimerkiksi seuraavassa silmukassa ehtona on luku < 10
eli silmukan koodi suoritetaan, jos luku on alle 10.
luku = int(input("Anna luku: "))
while luku < 10:
print(luku)
luku += 1
print("Suoritus valmis.")
Ohjelman tulostus voi olla seuraava:
Anna luku: 4 4 5 6 7 8 9 Suoritus valmis.
Koska ehto tarkastetaan aina ennen silmukan koodin suoritusta, on mahdollista, ettei koodia suoriteta kertaakaan. Esimerkiksi:
Anna luku: 12 Suoritus valmis.
Koska 12 ei ole pienempi kuin 10, ohjelma ei tulosta yhtään lukua.
Alustus, testaus ja muutos
Monessa silmukassa on kolme osaa: alustus, ehto ja muutos.
Alustus tarkoittaa silmukassa käytettävän muuttujan tai muuttujien alkuarvojen antamista. Tämä vaihe tehdään ennen silmukkaa. Ehto kirjoitetaan silmukan alkuun, ja se määrittelee, kuinka kauan silmukkaa suoritetaan. Joka kierroksella tapahtuva muutos vie silmukan askeleen lähemmäs sen loppumista. Esimerkiksi:
Jos jokin kolmesta osasta puuttuu, silmukka ei toimi oikein. Yksi tyypillinen virhe on muutoksen unohtaminen:
luku = 1
while luku < 10:
print(luku)
print("Suoritus valmis.")
Koska muuttujan luku
arvo ei koskaan muutu, jää ohjelma suoritettaessa ikuiseen silmukkaan eli toistaa samaa koodia, kunnes käyttäjä katkaisee ohjelman suorituksen (esimerkiksi painamalla Control
+ C
):
1 1 1 1 1 (tämä jatkuu ikuisesti...)
Ehdoista tarkemmin
Silmukan ehtona voidaan käyttää mitä tahansa ehtolauseketta. Esimerkiksi seuraava ohjelma tulostaa lukuja kolmen välein niin kauan kuin luku on pienempi kuin 100 eikä se ole jaollinen 5:llä:
luku = int(input("Anna luku: "))
while luku < 100 and luku % 5 != 0:
print(luku)
luku += 3
Kaksi esimerkkitulostusta eri syötteillä:
Anna luku: 28 28 31 34 37
Anna luku: 96 96 99
Luvun 28 kohdalla silmukka päättyy lukuun 37, koska seuraava luku 40 on jaollinen 5:llä. Luvun 96 kohdalla silmukka päättyy lukuun 99, koska seuraava luku 102 ei ole alle 100.
Silmukan ehtoa kirjoittaessa on tärkeä varmistua siitä, että silmukan suoritus päättyy. Esimerkiksi seuraava ohjelma on joko päättyvä tai ei-päättyvä riippuen alkuarvosta:
luku = int(input("Anna luku: "))
while luku != 10:
print(luku)
luku += 2
Jos syötteenä on parillinen luku, joka on enintään 10, silmukan suoritus päättyy:
Anna luku: 4 4 6 8
Muissa tapauksissa silmukka on kuitenkin ikuinen, koska muuttuja ei koskaan saavuta arvoa 10. Tällaisia syötteitä ovat esimerkiksi 3 ja 12.
Lisää debuggauksesta
Hieman haastavampaa ohjelmaa, esim. seuraavaksi vuorossa olevaa tehtävää Kahden potenssit, koodatessa voitaisiin lähteä liikkeelle seuraavasti:
asti = int(input("Mihin asti"))
luku = 1
while luku == asti:
# koodia
Tässä on aloitettu syötteen lukemisesta, minkä jälkeen ruvetaan miettimään silmukan lopetusehtoa sekä silmukan toimintaa.
Todennäköisesti ohjelma ei ensimmäisillä kokeilukerroilla toimi halutulla tavalla ja koodia on testailtava kymmeniä tai jopa satoja kertoja ennen kuin se alkaa toimia.
Koska koodi lukee syötteitä käyttäjältä, sen toiminnan kokeileminen on hidasta ja vaivalloista, koska jokaisella testauskerralla on ohjelmalle annettava näppäimistöltä käsin sen haluamat syötteet.
Yksi tapa toimia on "kovakoodata" syöte aluksi:
# kovakoodataan syötteen arvo aluksi
asti = 8 # int(input("Mihin asti"))
luku = 1
while luku == asti:
# koodia
Kun ohjelma toimii yhdellä syötteellä, sitä on helppo kokeilla muilla kovakoodatuilla syötteillä ja lopulta lukemalla syöte käyttäjältä.
Vastaava kikka toimii myös kurssien tehtäviin liittyvien testien ongelmatilanteita selvitellessä. Jos testi kertoo, että ohjelmasi toimii väärin, kun syöte on vaikkapa 42, niin kovakoodataan se syötteeksi bugin etsinnän ajaksi:
# testi ilmoitti että koodi toimii väärin kun syöte on 42
asti = 42 # int(input("Mihin asti"))
luku = 1
while luku == asti:
# koodia
Kurssin edellisessä osassa oli jo pariinkin otteeseen puhetta tulostuskomennon avulla tapahtuvasta debuggaamisesta. Kurssin aikana vastaan tulevat ohjelmat muuttuvat koko ajan haastavammiksi ja debuggauksen tarve tulee kasvamaan entisestään. Esimerkiksi silmukoiden lopetusehtojen saaminen toimimaan kaikissa tapauksissa voi olla haastavaa.
Tulostuskomentoihin perustuva debuggaus kannattaa ottaa omaan työkalupakkiin viimeistään nyt. Kertaa tarvittaessa edellisen osan ensimmäisessä ja neljännessä luvussa olleet debuggausohjeet.
Tulostamisen lisäksi on olemassa muitakin debuggaukseen sopivia työkaluja. Eräs tälläinen on sivuston Python Tutor tarjoama visualisointityökalu, jonka avulla oman ohjelman koodia on mahdollista suorittaa komento komennolta havainnoiden samalla, mitä arvoja ohjelman muuttujat saavat.
Seuraavassa kuvassa Python Tutorilla visualisoidaan edellisen osan debuggausmateriaalissa olevan hieman rikkinäisen koodin toimintaa:
Punainen nuoli kertoo, missä kohtaa ohjelman suoritus on menossa. Visualisaattori näyttää, mitä ohjelma on tulostanut ruudulle ja mitkä ovat ohjelman muuttujien arvot kullakin suorituksen hetkellä. Koodin suoritus etenee komento komennolta painiketta Next> painellessa.
Visualisaattorin käyttö on erittäin helppoa, koska riittää että tarkasteltava koodi kopioidaan koodi-ikkunaan. Huomaa, että visualisaattori ei saalli ääkkösten käyttämistä muuttujien eikä funktioiden nimissä.
Kokeneemmat ohjelmoijat tuskin käyttävät visualisaattoria koskaan, mutta aloittelijalle se voi olla oiva apuväline. Ohjelmointi ei nimittäin voi perustua tuuriin tai sattumaan. Ohjelmoijan on koko ajan tiedettävä tarkalleen, mitä muuttujien arvot ohjelman suorituksen aikana ovat. Jos muuttujien arvot eivät vastaakaan ohjelmoijan olettamaa, on tuloksena mitä suurimmalla todennäköisyydellä bugi.
Visualisaattori ja debuggaustulostukset ovat erinomainen väline siihen, että ohjelmoija voi omin silmin varmistaa, että ohjelma todellakin toimii kuten sen olettaa toimivan.
Merkkijonon rakentaminen paloista
Jo kurssin ensimetreillä opimme, että merkkijono on mahdollista "rakentaa" useammasta pienemmästä merkkijonosta +-operaattorin avulla. Esimerkiksi
sanat = "suo"
sanat = sanat + ", kuokka"
sanat = sanat + " ja python"
print(sanat)
suo, kuokka ja python
Huomaa, että edellinen on mahdollista kirjoittaa hieman tiiviimmin operaattorin += avulla:
sanat = "suo"
sanat += ", kuokka"
sanat += " ja python"
print(sanat)
Yhdistettävä merkkijonon pätkä voi olla myös f-merkkijono. Tämä saattaa olla kätevää, jos rakennettavaan merkkijonoon lisätään muuttujissa olevia arvoja. Voimme siis tehdä esim. seuraavasti:
kurssi = "Ohjelmoinnin perusteet"
arvosana = 4
lausunto = "Olet saanut "
lausunto += f"kurssilta {kurssi} "
lausunto += f"arvosanan {arvosana}"
print(lausunto)
Olet saanut kurssilta Ohjelmoinnin perusteet arvosanan 4
Edellisessä tehtävässä laskettiin lukujen summaa kasvattamalla sen arvoa silmukan sisällä.
Täsmälleen samalla idealla on mahdollista rakentaa myös merkkijonoa siten, että siihen lisätään yksi osa kerrallaan silmukassa...
Log in to view the quiz