Osa 2

Yksinkertainen silmukka

Silmukka eli toistolause on ehtolauseen lisäksi keskeinen ohjausrakenne ohjelmoinnissa. Aloitetaan toistamiseen tutustuminen tarkastelemalla Pythonin while-silmukkaa yksinkertaisten esimerkkien kautta. Ensi viikolla tutustutaan sitten monipuolisemmin sen mahdollisuuksiin.

Periaatteessa silmukka muistuttaa ehtolausetta. Ideana kuitenkin on, että sen avulla voidaan toistaa samaa koodia useamman kerran.

Tarkastellaan esimerkkiä, jossa ohjelma laskee käyttäjän syöttämien lukujen neliöitä niin kauan, että käyttäjä syöttää negatiivisen luvun:

while True:
    luku = int(input("Anna luku, -1 lopettaa: "))

    if luku == -1:
        break

    print(luku ** 2)

print("Kiitos ja moi!")

Ohjelman esimerkkisuoritus:

Esimerkkitulostus

Anna luku, -1 lopettaa: 2 4 Anna luku, -1 lopettaa: 4 16 Anna luku, -1 lopettaa: 10 100 Anna luku, -1 lopettaa: -1 Kiitos ja moi!

Kuten esimerkistä huomataan, ohjelman kysyy while-lauseen ansiosta käyttäjältä useita lukuja. Sitten kun käyttäjän syöte on -1, suoritetaan break-komento, jolloin suoritus hyppää ensimmäiselle lohkon jälkeiselle riville.

Silmukoita käytettäessä on oltava tarkkana, että ei jouduta tilanteeseen, missä silmukan suoritus ei koskaan lopu. Muutetaan edellistä esimerkkiä seuraavasti

luku = int(input("Anna luku, -1 lopettaa: "))
while True:
    if luku == -1:
        break

    print(luku ** 2)

print("Kiitos ja moi!")

Nyt siis lukua kysytään silmukan ulkopuolella. Jos käyttäjä antaa minkä tahansa muun luvun kuin -1:n, ei silmukasta tulla koskaan pois, eli syntyy ikuinen silmukka. Tällöin silmukassa olevaa lohkoa suoritetaan ikuisesti:

Esimerkkitulostus

Anna luku, -1 lopettaa: 2 4 4 4 4 4 4 4 4 (jatkuu ikuisesti...)

Seuraavassa esimerkkinä ohjelma, joka antaa käyttäjän jatkaa eteenpäin vasta sen jälkeen, kun käyttäjä on syöttänyt oikean PIN-koodin 1234:

while True:
    koodi = input("Anna PIN-koodi: ")
    if koodi == "1234":
        break
    print("Väärin... yritä uudelleen")

print("PIN-koodi oikein!")
Esimerkkitulostus

Anna PIN-koodi: 0000 Väärin... yritä uudelleen Anna PIN-koodi: 9999 Väärin... yritä uudelleen Anna PIN-koodi: 1234 PIN-koodi oikein!

silmukka ja apumuuttujat

Tehdään vielä PIN-koodin tarkastavasta ohjelmasta monimutkaisempi versio, joka antaa käyttäjälle vain kolme mahdollisuutta yrittää PIN-koodin syöttämistä.

Ohjelma käyttää nyt kahta apumuuttujaa. Muuttuja yritykset pitää kirjaa siitä, kuinka monta kertaa käyttäjä on syöttänyt koodin. Muuttuja onnistui saa arvokseen joko True tai False riippuen siitä, onnistuuko kirjautuminen.

yritykset = 0

while True:
    tunnus = input("Anna PIN-koodi: ")
    yritykset += 1

    if tunnus == "1234":
        onnistui = True
        break

    if yritykset == 3:
        onnistui = False
        break

    # tänne tullaan jos väärin JA ei ole jo kolmea yritystä
    print("Väärin... yritä uudelleen")

if onnistui:
    print("Pinkoodi oikein!")
else:
    print("Liian monta yritystä...")
Esimerkkitulostus

Anna PIN-koodi: 0000 Väärin... yritä uudelleen Anna PIN-koodi: 1234 PIN-koodi oikein!

Esimerkkitulostus

Anna PIN-koodi: 0000 Väärin... yritä uudelleen Anna PIN-koodi: 9999 Väärin... yritä uudelleen Anna PIN-koodi: 4321 Liian monta yritystä...

Silmukasta tullaan siis ulos, jos käyttäjä syöttää oikean PIN-koodin tai jos yrityksiä tehdään liian monta. Silmukan jälkeinen if-lause tarkastaa muuttujan onnistui arvon perusteella, onko kirjautuminen onnistunut vai ei.

pro-tip: debuggaustulostus silmukassa

Kun ohjelmat alkavat sisältää silmukoita, kasvavat mahdolliset bugienkin lähteet ihan uudelle tasolle, ja tämän osan ensimmäisessä luvussa mainittujen debugtulostuksien teko muuttuu entistäkin tärkeämmäksi.

Esim. jos edellinen esimerkki olisi koodattu hieman väärin:

yritykset = 0

while True:
    tunnus = input("Anna PIN-koodi: ")
    yritykset += 1

    if yritykset == 3:
        onnistui = False
        break

    if tunnus == "1234":
        onnistui = True
        break

    print("Väärin... yritä uudelleen")

if onnistui:
    print("Pinkoodi oikein!")
else:
    print("Liian monta yritystä...")

ohjelma toimii kummalliseti, se antaa yrittää PIN-koodia kolmesti, mutta valittaa että yrityksiä on liian monta vaikka lopussa syötettiin oikea koodi:

Esimerkkitulostus

Anna PIN-koodi: 0000 Väärin... yritä uudelleen Anna PIN-koodi: 9999 Väärin... yritä uudelleen Anna PIN-koodi: 1234 Liian monta yritystä...

Bugin syy selviää lisäämällä sopivia debug-tulostuksia:

while True:
    print("whilen lohko alkaa:")
    tunnus = input("Anna PIN-koodi: ")
    yritykset += 1

    print("yritykset:", yritykset)
    print("ehto1:", yritykset == 3)
    if yritykset == 3:
        onnistui = False
        break

    print("tunnus:", tunnus)
    print("ehto2:", tunnus == "1234")
    if tunnus == "1234":
        onnistui = True
        break

    print("Väärin... yritä uudelleen")
Esimerkkitulostus

whilen lohko alkaa: Anna PIN-koodi: 2233 yritykset: 1 ehto1: False tunnus: 2233 ehto2: False Väärin... yritä uudelleen whilen lohko alkaa: Anna PIN-koodi: 4545 yritykset: 2 ehto1: False tunnus: 4545 ehto2: False Väärin... yritä uudelleen whilen lohko alkaa: Anna PIN-koodi: 1234 yritykset: 3 ehto1: True Liian monta yritystä...

Kun tulostuksia silmäillään hieman huomataan, että kolmannella while-lohkon suorituksella ensimmäisen if-komennon ehto on arvoltaan tosi, ja silmukasta poistutaan ennen kuin ehditään tarkastaa oliko juuri syötetty salasana oikein:

  while True:
    # ....

    # tämä lohko on liian aikaisin
    if yritykset == 3:
        onnistui = False
        break

    # tänne ei päästä enää kolmannella yrityksellä...
    if tunnus == "1234":
        onnistui = True
        break

Merkkijonon kokoaminen plus-operaattorilla

PIN-koodin tarkastavassa esimerkissä käytimme apumuuttujaa yritykset pitämään kirjaa siitä kuinka monta kertaa PIN-koodi on syötetty:

yritykset = 0

while True:
    tunnus = input("Anna PIN-koodi: ")
    yritykset += 1
    # ...

Muuttuja alustetaan arvoon nolla silmukan ulkopuolella, ja jokainen silmukan suoritus kasvattaa sen arvoa yhdellä.

Vastaava idea toimii myös merkkijonoille. Voisimme laajentaa ohjelmaa siten, että se kokoaa yhteen merkkijonoon kaikki käyttäjän syöttämät PIN-koodit:

tunnukset = ""
yritykset = 0

while True:
    tunnus = input("Anna PIN-koodi: ")
    yritykset += 1
    tunnukset += tunnus + ", "
    # ...

Apumuuttuja saa aluksi arvokseen tyhjän merkkijonon, eli merkkijonon jonka pituus on nolla:

tunnukset = ""

Silmukan sisällä merkkijonoa kasvatetaan lisäämällä siihen aina silmukassa syötetty tunnus ja pilkku:

    tunnus = input("Anna PIN-koodi: ")
    tunnukset += tunnus + ", "

Jos käyttäjä syöttäisi tunnukset 1111 2222 1234 olisi muuttujan tunnukset arvo lopulta

Esimerkkitulostus

1111, 2222, 1234,

:
Loading...
:
Loading...

Log in to view the quiz

Vastaa lopuksi koko toista osaa koskevaan loppukyselyyn:

:
Loading...
:
Loading...

Log in to view the quiz