Termipankki
  1. A
    1. Absoluuttinen polku
    2. Ajonaikainen
      konseptit
    3. Alkio
      arvot listat
    4. Alustaminen
      muuttujat arvot
    5. Argumentti
      arvot funktiot
    6. Arvo
      arvot
    7. Avain
      sanakirjat arvot
    8. Avainsana
      nimet
    9. Avainsana-argumentti
      funktiot
    10. Avausmoodi
      tiedostot
    11. Aliohjelma
      Funktio
    12. Attribuutti
      Jäsenarvo
    13. Ajaminen
      Suorittaminen
  2. B
    1. Boolen operaattori
      Looginen operaattori
    2. Bugi
      Ohjelmointivirhe
    3. break
      toistorakenteet avainsanat
  3. C
    1. Carriage return
      pakeneminen merkkijonot tiedostot windows
    2. Ctrl + C
      Näppäimistökeskeytys
    3. Callback
      Takaisinkutsu
    4. continue
      toistorakenteet avainsanat
  4. D
    1. Data
    2. Debuggaus
    3. Dokumenttimerkkijono
      dokumentointi
  5. E
    1. Elementti
      Alkio
    2. Ehto
      ohjausrakenteet
    3. Ehtolause
      ohjausrakenteet
    4. Ehtorakenne
      ehtorakenteet ohjausrakenteet
    5. Epätosi
      arvot
    6. Erotin
      merkkijonot tiedostot listat syöte
    7. Evaluointi
      lausekkeet arvot
    8. Exception-luokka
      poikkeukset ohjausrakenteet
    9. enumerate
      listat toistorakenteet
  6. F
    1. False
      Epätosi
    2. Format
      merkkijonot tulostus
    3. Funktio
      funktiot
    4. Funktiokutsu
      funktiot lauseet
    5. Funktiomäärittely
    6. f-merkkijono
      merkkijonot
    7. for
  7. G
    1. Generaattori
      objektit toistorakenteet
    2. Globaali muuttuja
      muuttujat arvot
    3. Globaali näkyvyys
  8. H
    1. Haara
      try-rakenteet ehtorakenteet
    2. Hyppy
      ohjausrakenteet
    3. Hardkoodaus
      Kovakoodaus
  9. I
    1. if-lause
      Ehtolause
    2. if-rakenne
      Ehtorakenne
    3. Ikuinen silmukka
      toistorakenteet
    4. Indeksi
      arvot listat
    5. Indeksiosoitus
      arvot listat
    6. import
      moduulit
  10. J
    1. Jäsenarvo
      objektit
    2. Jäsenfunktio
      Metodi
  11. K
    1. Kutsu
      Funktiokutsu
    2. Kierros
      toistorakenteet
    3. Kirjasto
      moduulit
    4. Komentoriviargumentti
      terminaali
    5. Kommentti
      virheenetsintä dokumentointi
    6. Kooditiedosto
      konseptit
    7. Kovakoodaus
      arvot
    8. Kutsupyyntö
      funktiot
    9. Käsittelijä
      funktiot konseptit
    10. Käyttöliittymä
      konseptit
    11. Käyttöliittymäelementti
    12. Koodilohko
      Lohko
    13. Koodi
      Lähdekoodi
    14. KeyboardInterrupt
      Näppäimistökeskeytys
    15. Komentorivi
      Terminaali
    16. Komentokehote
      Terminaali
    17. Kahva
      Tiedostokahva
  12. L
    1. Lause
      konseptit
    2. Lauseke
      konseptit
    3. Leikkaus
      listat
    4. Lista
    5. Literaaliarvo
      arvot
    6. Liukuluku
      arvot tyypit
    7. Lohko
      ohjausrakenteet funktiot
    8. Looginen operaattori
      ohjausrakenteet operaattorit
    9. Lähdekoodi
      konseptit
  13. M
    1. Muotoilu
      Format
    2. Merkki
    3. Merkkijono
      arvot tyypit
    4. Metodi
      funktiot objektit
    5. Metodikutsu
      lausekkeet objektit
    6. Moduuli
    7. Monikko
      tietorakenteet listat
    8. Muuntumaton
      arvot merkkijonot konseptit
    9. Muuntuva
      arvot konseptit listat
    10. Muuttuja
      arvot konseptit
    11. Määrittely
      konseptit
  14. N
    1. Nimeämätön vakio
      arvot vakiot
    2. Nimi
      muuttujat funktiot
    3. Nimiavaruus
      moduulit funktiot konseptit
    4. Nimikonflikti
    5. Näkyvyysalue
      konseptit lohkot
    6. Näppäimistökeskeytys
      poikkeukset
  15. O
    1. Objekti
      konseptit
    2. Olio
      Objekti
    3. Ohjausrakenne
      try-rakenteet toistorakenteet ehtorakenteet
    4. Ohjelmointiongelma
      ongelmanratkaisu
    5. Ohjelmointityyli
    6. Ohjelmointivirhe
      ongelmanratkaisu
    7. Oletusarvo
      arvot funktiot parametrit
    8. Ominaisuus
      objektit
    9. Operaatio
      lausekkeet
    10. Operaattori
    11. Operandi
  16. P
    1. Paikallinen muuttuja
    2. Paikanpidin
      merkkijonot tulostus
    3. Pakeneminen
      merkkijonot
    4. Palauttaminen
      arvot funktiot
    5. Paluuarvo
    6. Parametri
      funktiot
    7. Parametrisaatio
    8. Poikkeus
      try-rakenteet ongelmanratkaisu
    9. Poikkeusten käsittely
      ohjausrakenteet poikkeukset
    10. Polku
    11. Python-konsoli
      työkalut
    12. Python-tulkki
      työkalut
    13. Pääohjelma
      konseptit
    14. Presedenssi
      Sidontajärjestys
  17. R
    1. Rajapinta
      moduulit funktiot konseptit
    2. Ratkaisumalli
      ongelmanratkaisu
    3. Rekursio
      funktiot konseptit
    4. Relatiivinen polku
    5. Rivinvaihtomerkki
      merkkijonot tiedostot
  18. S
    1. Sanakirja
      tietorakenteet
    2. Sapluuna
      merkkijonot konseptit
    3. Sekvenssi
      tietorakenteet konseptit toistorakenteet
    4. Sidontajärjestys
      lausekkeet konseptit
    5. Suoritusjärjestys
      Sidontajärjestys
    6. Sijoittaminen
      muuttujat arvot
    7. Sijoitusoperaattori
      muuttujat arvot operaattorit
    8. Silmukkamuuttuja
      muuttujat toistorakenteet
    9. Sisennys
      konseptit
    10. Sisäänrakennettu funktio
      funktiot
    11. Suorittaminen
      lausekkeet konseptit
    12. Suoritusjärjestys
    13. Syntaksi
      konseptit
    14. Syntaksivirhe
      poikkeukset
    15. Syöte
      merkkijonot konseptit
    16. Silmukka
      Toistorakenne
    17. Stacktrace
      Traceback
  19. T
    1. Taikaluku
      Nimeämätön vakio
    2. try-rakenne
      Poikkeusten käsittely
    3. Takaisinkutsu
      funktiot
    4. Tallennusformaatti
      merkkijonot tiedostot
    5. Tapahtuma
      konseptit
    6. Tekstitiedosto
      tiedostot
    7. Terminaali
      työkalut
    8. Testaaminen
      ongelmanratkaisu konseptit
    9. Tiedostokahva
      objektit tiedostot
    10. Tiedostonimi
      merkkijonot tiedostot
    11. Tiedostopääte
      tiedostot
    12. Tietorakenne
      sanakirjat konseptit listat
    13. Tila
      konseptit
    14. Toistorakenne
      ohjausrakenteet
    15. Tosi
      arvot
    16. True
      Tosi
    17. Totuusarvo
      ohjausrakenteet
    18. Traceback
      ongelmanratkaisu
    19. Tulostaminen
      merkkijonot konseptit
    20. Tynkäfunktio
      ongelmanratkaisu funktiot
    21. Tyylisääntö
    22. Tyyppi
      arvot konseptit
    23. Tyyppimuunnos
      arvot funktiot tyypit
  20. V
    1. Vakio
      muuttujat arvot
    2. Valinnainen argumentti
      arvot funktiot parametrit
    3. Vertailuarvo
    4. Vertailuoperaattori
      ohjausrakenteet operaattorit
    5. Viittaaminen
      muuttujat arvot objektit
    6. Virheviesti
      ongelmanratkaisu
  21. W
    1. while
      toistorakenteet
    2. with
      tiedostot
Ratkaistu: / tehtävää

3. Materiaali: Kehää kiertävät listat

Kaikki tämä on toistoa

Ohjelmointitaitojen evoluutio tällä kurssilla on tahdiltaan ripeä. Ensimmäisen materiaalin suoraviivaisista laskutoimituksista päästiin viime viikolla jo haarautuviin ohjelmiin, jotka kykenivät kyselemään käyttäjältä tietoja ja toimimaan niiden perusteella. Ohjelmamme ovat toistaiseksi käsitelleet dataa ainoastaan yksittäisinä arvoina, joiden lukumäärä on aina ollut ennalta määrätty. Olemme esimerkiksi käyttäneet muuttujia luku_1 ja luku_2 käsitellessämme tasan kahta numeroarvoa.
Tosielämässä on kuitenkin helppo keksiä skenaarioita, joissa käsitellään ennalta tuntematonta määrää dataa. Vaikka määrä olisi tunnettukin, suuret datamäärät aiheuttavat silti ongelmia: jos meillä on tuhat numeroarvoa, tarvitaan nykyisellä osaamisella myös tuhat koodiriviä näiden kaikkien käsittelyyn.
Tämän materiaalin aiheina ovat kunnianhimoisesti sekä listat että toistorakenteet. Ne ovat ohjelmointipalapelimme viimeiset palaset. Niitä ei tosin käydä aivan täysin läpi, mutta saaduilla työkaluilla pystyy kuitenkin teoriassa ratkomaan melkein mitä tahansa ongelmia. Käytännössä toki tosimaailman ohjelmointiin kuuluu paljon muutakin kuin tässä ja edellisissä materiaaleissa esitellyt peruskäsitteet. Kaikki asiat kuitenkin pohjimmiltaan perustuvat näille peruskäsitteille, ja useimmiten myöhemmin opeteltavissa asioissa on pikemminkin kyse siitä, ettei tarvitse tehdä joka asiaa itse aloittamalla aina peruspalikoista.
Merkittävimmäksi rajoitteeksemme tämän luvun jälkeen jää se, ettei meillä ole vielä pääsyä tietokoneella oleviin tiedostoihin, joten esimerkiksi mittausdatan käsittely ei ole ulottuvillamme. Meiltä myös puuttuu vielä kyky muokata listoja, joten mm. miinojen sijoittelu listoilla kuvattuun kenttään ei ihan vielä tule onnistumaan.

Kyselytunti 2: Kysymykset ovat ikuisia

Viime materiaalin yhtenä lopputuloksena syntyi ohjelma, joka suoritti yksikkömuunnoksia imperiaalisista yksiköistä SI-järjestelmään. Ohjelmassa oli yksi yleisesti toistuva kehoite: Anna muutettava arvo: . Jätimme viime kerralla toteuttamatta arvon tarkistuksen esimerkin selkeyden nimissä, mutta tietenkin, jos kyseessä olisi ollut oikeaan käyttöön suunnattu ohjelma, sen olisi pitänyt ehdottomasti selvitä myös virhetilanteista kaatumatta. Toinen ilmeinen epäkohta ohjelmassa oli, että se piti aina käynnistää uudestaan yhden yksikkömuunnoksen jälkeen.
Oppimistavoitteet: Tässä osiossa opitaan luomaan yhdenlainen silmukka ja toteuttamaan sitä käyttämällä ohjelma, joka toistaa tiettyjä koodinpätkiä itsestään ennaltamääräämättömän määrän kertoja. Käymme läpi tämän yleisen ratkaisun filosofiaa ja esitämme tietysti, miten sellainen toteutetaan Pythonissa konkreettisesti. Tämän osuuden jälkeen osaat mm. tehdä fiksuja kyselyfunktioita, jotka pyytävät syötettä käyttäjältä itsepintaisesti niin kauan, että saatu syöte on oikeanlainen.

Koodille ehdollista pakkotoistoa

Kuvalähde 1
Toistorakenteet
ovat
ehtorakenteiden
sukulaisia, ja näillä kahdella onkin yhteinen nimi:
ohjausrakenteet
. Nimi viittaa siihen, että ne ovat rakenteita, jotka ohjaavat tavalla tai toisella ohjelman suoritusta. Siinä missä ehtorakenteet luovat haaroja, toistorakenteet luovat toistoa. Niitä kutsutaan tästä syystä myös silmukoiksi.
Silmukoita on Pythonissa (ja useissa muissakin kielissä) kahta lajia. Näistä ensimmäinen on erityisen läheistä sukua ehtorakenteille. Siinä missä
ehtolause
määrittää
ehdon
, jolla sen alaisuudessa oleva koodi suoritetaan, vastaava toistorakenne määrittää ehdon, jonka ollessa voimassa sen alaisuudessa olevaa koodia suoritetaan toistuvasti – niin kauan siis kuin ehto on tosi. Ehdon totuudellisuus tarkistetaan uudestaan jokaisen kierroksen alussa. Koodiesimerkkinä:
syote = ""
while len(syote) < 8:
    syote = input("Kirjoita vähintään 8 merkkiä pitkä sana: ")
print("Kirjoitit sanan", syote)
Tässä käytetään ehdossa len-
funktiota
, joka palauttaa
argumentiksi
annetun
merkkijonon
(tai muun
sekvenssin
) pituuden. Koodi siis kysyy käyttäjältä
syötettä
, kunnes tämä antaa syötteen, jossa on vähintään 8 merkkiä. Huomaa, että ehto on tästä käänteinen: niin kauan kuin syote-merkkijonon pituus on pienempi kuin 8, suoritetaan koodiriviä, jolla käyttäjältä kysytään syötettä.
Silmukoista while sopii juuri tämän kaltaisiin tapauksiin, joissa lopetus riippuu jostain silmukan sisällä tapahtuvasta ennakoimattomattomasta tapahtumasta. Tässä esimerkissä koodin kirjoittajan on täysin mahdotonta tietää, kuinka monta kertaa käyttäjä tulee syöttämään sanan, jossa on alle 8 merkkiä. Lopetuksen täytyy tapahtua juuri sillä toistolla, jolla käyttäjä syöttää oikeanlaisen merkkijonon. Niinpä
while-silmukka
sopii tilanteisiin, joissa toistojen lukumäärää ei voida mitenkään päätellä ennen silmukan suorittamista.

Hätäkoodi

Hyvin tyypillinen käyttöskenaario while-silmukalle on sellainen, jossa käyttäjältä kysytään jotain syötettä kunnes tämä ilmaisee haluavansa lopettaa. Tässä esimerkissä käyttäjä syöttää morsekoodia kirjain kerrallaan ja antaa !-merkin mikäli syötetty kirjain on viestin viimeinen. Tämän jälkeen ohjelma voi vaikka lähettää viestin johonkin eetteriin, koska morsen lähetys nykytietokoneilla on todetusti hyvin tehokasta viestintää...
Opittavat asiat: Käyttäjän syötteestä riippuvan
while-silmukan
määrittely.
Ehtojen
suunnittelua ja kirjoittamista pääsee myös kertaamaan.

Alustus:
Määrittelyrivi tulee kirjoittaa siten, että se sopii tähän kehikkoon:
kirjain = ""
# tähän kohtaan tulee while-silmukan määrittely
    kirjain = input("Mors mors! Huutomerkki (!) lopettaa: ")

Haettu vastaus:
Vastaukseen haetaan siis kommentilla merkittyyn kohtaan sopiva while-silmukan määrittely. Silmukan tulee jatkua niin kauan kuin kirjain-muuttujassa oleva syöte ei pääty lopetusmerkkiin !. Vastauksen tulisi siis olla tasan yksi rivi.
Kirjoita siis pelkästään silmukan aloitusrivi vastaukseesi.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Haluamme rakentaa ohjelman, jossa käyttäjältä kysytään numeroarvoa niin kauan, että tämä oikeasti syöttää kelvollisen numeroarvon.
Toistorakenteisin
, ja nimenomaan ehdolliseen toistorakenteeseen, tässä määrittelyssä viittaa hyvinkin selkeästi ilmaisu "niin kauan, että". Ohjelmassa on selkeästi tarve toistaa jokin kohta koodissa, ja lisäksi toistojen lukumäärä ei ole tiedossa koodia kirjoittaessa, vaan se riippuu käyttäjästä. Tämän kääntämisessä koodiksi on tosin pienoinen mutka: syötteiden numerokelvollisuutta on aiemmin tarkasteltu try-rakenteilla eikä
ehdoilla
. Teoriassa kelvollisen syötteen voi tarkistaa ilman try-rakenteen käyttöäkin, mutta sen sovittaminen
ehtolauseen
ehdoksi on vaikeaa.

Vankilapako

Selvitetään ongelman ratkaisemiseksi, millä kaikilla tavoilla
silmukan
suoritus voi päättyä. Toistaiseksi tunnemme vain yhden tavan:
while-silmukan
suoritus päättyy, kun sen
ehto
ei ole enää tosi. Silmukka voi kuitenkin päättyä muillakin tavoilla. Jos silmukassa tapahtuu
poikkeus
, jota ei käsitellä silmukan sisällä try-rakenteella, silmukan suoritus päättyy:
In [1]: while True:
   ...:     luku = float(input("Anna luku: "))
   ...:
Anna luku: 15
Anna luku: aasi
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-1-bd285c9d1f25> in <module>()
      1 while True:
----> 2     luku = float(input(": "))
      3
Tämän esimerkin silmukan ehto on True, joten se ei selkeästikään voi päättyä siihen, että ehto muuttuisi epätodeksi. Silmukkaa suorittaessa kuitenkin tapahtuu poikkeus. Käyttäjän
syötettä
ei voida muuttaa liukuluvuksi, mikä päättää silmukan välittömästi. Jos sen sijaan silmukan sisällä olisi try-rakenne seuraavalla tavalla, silmukkaa ei voisi päättää virheellisellä syötteellä:
In [1]: while True:
   ...:     try:
   ...:         luku = float(input("Anna luku: "))
   ...:     except ValueError:
   ...:         print("Et antanut lukua")
   ...:
Anna luku: 15
Anna luku: aasi
Et antanut lukua
Anna luku: 40
Anna luku:
Kuvalähde 2

Avain pakoon

Miten päästä pois esimerkin silmukasta? Syöttämällä tekstiä ei enää saa ohjelmaa kaatumaan, joten mitä käyttäjä voi tehdä? On olemassa kaksi eri poikkeusta, jotka käyttäjä voi saada aikaan sopivia nappeja painelemalla ja joilla silmukasta voi paeta. Näistä tärkeämpi on jo tiedossa, mutta se on syytä kerrata!
Opittavat asiat: Palauttaa mieleen miten
syötteen
kysely voidaan keskeyttää
poikkeuksen
avulla.

Alustus:
Voit tarvittaessa virkistää muistiasi 2. materiaalin tehtävästä "Ohjelmistoväkivaltaa".

Haettu vastaus:
Vastaukseen haetaan yhden poikkeuksen nimeä.
Tähän laatikkoon siis poikkeuksen nimi
Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Silmukan
lopettamiseen löytyy myös siistimpiä tapoja kuin yllä olevan tehtävän vastaus. Mikäli silmukka on
funktiossa
, sen suoritus päättyy kun kohdataan funktion return-lause silmukan sisällä. Silmukan suoritus päättyy myös mikäli kohdataan break-lause. Näistä jälkimmäinen on uusi temppu, mutta varsin yksinkertainen. Kun ohjelman suoritus kohtaa
break-lauseen
, se hyppää välittömästi ulos sillä hetkellä meneillään olevasta silmukasta, ja jatkaa suoritusta silmukan jälkeisestä koodista. Lisätään break-lause ylhäällä olevaan try-rakenteeseen elsen avulla:
In [1]: while True:
   ...:     try:
   ...:         luku = float(input("Anna luku: "))
   ...:     except ValueError:
   ...:         print("Et antanut lukua")
   ...:     else:
   ...:         break
   ...:
Anna luku: aasi
Et antanut lukua
Anna luku: 40
On muistettava, että try-rakenteen else-osaan mennään mikäli try-osan sisällä oleva koodi suorittuu kokonaan ilman ongelmia. Sijoitetaan tämä koodinpätkä aiemmin kasattuun koodiin. Esimerkkinä olkoon pituus-funktio:
def pituus():
    print("Valitse pituusyksikkö seuraavien joukosta syöttämällä suluissa annettu lyhenne")
    print("Tuuma (in tai \")")
    print("Jalka (ft tai ')")
    print("Jaardi (yd)")
    print("Maili (mi)")
    print()
    yksikko = input("Anna muutettava yksikkö: ")
    while True:
        try:
            arvo = float(input("Anna muutettava arvo: "))
        except ValueError:
            print("Arvon tulee olla pelkkä luku")
        else:
            break
    try:
        kerroin = PITUUSKERTOIMET[yksikko]
    except KeyError:
        print("Valitsemaasi yksikköä ei voida muuntaa")
    else:
        print(f"{arvo:.3f} {yksikko} on {arvo * kerroin:.3f} m")
Tämä toimii, mutta näyttää epämiellyttävältä, koska sama muutos pitäisi tehdä kolmeen muuhunkin funktioon. Voi myös kuvitella, miten epäluettavalta koodi näyttäisi, jos samanlaisia kyselyjä pitäisi tehdä peräkkäin useampia! Sen sijaan, jos tämä koodipätkä siirretään
funktioon
, esimerkiksi nimellä kysy_arvo, saataisiin kysely piilotettua tämän näköiseen koodinpätkään:
def kysy_arvo():
    while True:
        try:
            luku = float(input("Anna muutettava arvo: "))
        except ValueError:
            print("Arvon tulee olla pelkkä luku")
        else:
            break
    return luku
Loppuun on tietenkin lisättävä
return
, jotta silmukan sisällä saatu luku-
muuttujan
arvo
saadaan käyttöön muuallakin. Toisaalta, koska myös returnin kohtaaminen lopettaa silmukan ja samalla koko funktion suorituksen, voidaan
break
-rivi korvata returnilla:
def kysy_arvo():
    while True:
        try:
            luku = float(input("Anna muutettava arvo: "))
        except ValueError:
            print("Arvon tulee olla pelkkä luku")
        else:
            return luku
Jos käytämme nyt tätä funktiota aiemmassa koodissa, tulos näyttää yhtä nätiltä kuin ennen tarkistuksen lisäämistä, tai ehkä jopa hieman paremmalta, koska kysy_arvo on kuvaava nimi sille, mitä funktiossa tapahtuu:
def pituus():
    print("Valitse pituusyksikkö seuraavien joukosta syöttämällä suluissa annettu lyhenne")
    print("Tuuma (in tai \")")
    print("Jalka (ft tai ')")
    print("Jaardi (yd)")
    print("Maili (mi)")
    print()
    yksikko = input("Anna muutettava yksikkö: ")
    arvo = kysy_arvo()
    try:
        kerroin = PITUUSKERTOIMET[yksikko]
    except KeyError:
        print("Valitsemaasi yksikköä ei voida muuntaa")
    else:
        print(f"{arvo:.3f} {yksikko} on {arvo * kerroin:.3f} m")
Sama muutos voidaan tehdä myös muihin funktioihin. Toiminta on lähes sama: ainoastaan fahrenheit-muunnoksessa käytetty "Anna lämpötila: " -kehoite korvaantuu nyt kysy_arvo-funktion yleisemmällä "Anna muutettava arvo: " -kehoitteella.

Salakalassa

Salasanoja tarvitaan nykyään kaikkialla. Usein niille asetetaan myös erinäisiä vahvuusvaatimuksia, jotta niitä ei pysty arvaamaan ns. brute force -tekniikalla (eli kaikkia merkkiyhdistelmiä ohjelmallisesti kokeilemalla), ainakaan triviaalissa ajassa. Hyvin yksinkertaistettu skenaario on, että salasanalta vaaditaan jonkinlaista minimipituutta. Tutustutaan tähän yksinkertaiseen tarkistukseen. Tyydytään tällä kertaa 8 merkkiin, mutta todettakoon, että nykyaikana vähintään 32 merkkiä ei olisi lainkaan liioittelua. Salasanan pituus on myös paljon merkittävämpi tekijä - erikoismerkkien vaatiminen yms. on yleensä aika huuhaata.
Opittavat asiat: Yksinkertaisen
syötteen
kyselyfunktion rakentaminen
ehtolauseen
ja
breakin
avulla.

Toteutettava funktio: kysy_salasana
  • Palauttaa
    :
    • käyttäjän syöttämä salasana (merkkijono)
Kirjoita
funktio
, joka kysyy käyttäjältä
merkkijonoa
niin kauan, että käyttäjä syöttää merkkijonon joka on vähintään 8 merkin pituinen. Kysymys- ja palautemerkkijonot voit kopioida alla olevasta toimintaesimerkistä. Funktio on helpompi toteuttaa käyttämällä while True-silmukkaa ja erillistä ehtolausetta kuin
while-silmukkaa
, jossa on
ehto
. Apuna toimii siis juuri esitelty break.

Funktion testaaminen:
Pääohjelmassa voit kutsua funktiota, jotta pääset kokeilemaan sitä.
print(kysy_salasana())
Kun testaat koodiasi, muista tarkistaa rajatapaukset, eli 7 merkkiä pitkä pitäisi hylätä, ja 8 merkkiä pitkä hyväksyä!

Esimerkit toiminnasta:
Kirjoita salasana: banaani
Salasanan tulee olla vähintään 8 merkkiä pitkä
Kirjoita salasana: banaanilaiva
Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Tuomiomme on elinkautinen

Toinen ohjelmamme käyttömukavuutta lisäävä tekijä olisi se, että ohjelman suoritus ei lopu yhden operaation jälkeen. Käyttäjä on nähnyt jonkin verran vaivaa päästäkseen siihen vaiheeseen asti, että on pystynyt tekemään haluamansa muunnoksen. Olisi siis kohteliasta, jos samalla vaivalla voisi tehdä useampia muunnoksia ilman, että tarvitsee toistaa kaikkia askeleita joka kerta. Tähän ei tarvita mitään uusia ohjelmointitemppuja. Aloitetaan pääohjelmasta, jonka jätimme aiemmin tämän näköiseksi:
print("Tämä ohjelma muuntaa yhdysvaltalaisia yksiköitä SI-yksiköiksi")
print("Mahdolliset toiminnot:")
print("(P)ituus")
print("(M)assa")
print("(T)ilavuus")
print("(L)ämpotila")
print()
valinta = input("Tee valintasi: ").strip().lower()
if valinta == "p" or valinta == "pituus":
    pituus()
elif valinta == "m" or valinta == "massa":
    massa()
elif valinta == "t" or valinta == "tilavuus":
    tilavuus()
elif valinta == "l" or valinta == "lämpötila":
    lampotila()
else:
    print("Valitsemaasi toimintoa ei ole olemassa")
Ohjelman suoritus toistuvasti onnistuu varsin helposti, kun koodiin lisätään
while-silmukka
seuraavasti:
print("Tämä ohjelma muuntaa yhdysvaltalaisia yksiköitä SI-yksiköiksi")
print("Mahdolliset toiminnot:")
print("(P)ituus")
print("(M)assa")
print("(T)ilavuus")
print("(L)ämpotila")
print()
while True:
    valinta = input("Tee valintasi: ").strip().lower()
    if valinta == "p" or valinta == "pituus":
        pituus()
    elif valinta == "m" or valinta == "massa":
        massa()
    elif valinta == "t" or valinta == "tilavuus":
        tilavuus()
    elif valinta == "l" or valinta == "lämpötila":
        lampotila()
    else:
        print("Valitsemaasi toimintoa ei ole olemassa")
Valitettavasti nyt käyttäjällä ei ole mitään mahdollisuutta lopettaa ohjelmaa ilman väkivaltaisia näppäinyhdistelmiä. Aikaisemmin ohjelman suoritus loppui itsestään, mutta nyt se täytyy toteuttaa koodissa erikseen. Valikkoon pitää lisätä siis toiminto, jolla ohjelma lopetetaan. Tälle toiminnolle voidaan valita oma kirjainlyhenne. Valitettavasti helpot eli sekä l (lopeta) että p (poistu) ovat jo käytössä. Otetaan käyttöön siis vaikka q (quittaa). Aiemmin opitun perusteella tiedämme, että
break
-lauseella pääsee ulos
silmukasta
ja siten koko ohjelmasta, koska silmukan jälkeen ei ole yhtään koodiriviä. Sijoitetaan siis
ehtorakenteeseen
uusi
elif-haara
lopetusta varten, ja lisätään uusi toiminto myös ohjeisiin:
print("Tämä ohjelma muuntaa yhdysvaltalaisia yksiköitä SI-yksiköiksi")
print("Mahdolliset toiminnot:")
print("(P)ituus")
print("(M)assa")
print("(T)ilavuus")
print("(L)ämpotila")
print("(Q)uittaa")
print()
while True:
    valinta = input("Tee valintasi: ").strip().lower()
    if valinta == "p" or valinta == "pituus":
        pituus()
    elif valinta == "m" or valinta == "massa":
        massa()
    elif valinta == "t" or valinta == "tilavuus":
        tilavuus()
    elif valinta == "l" or valinta == "lämpötila":
        lampotila()
    elif valinta == "q" or valinta == "quittaa":
        break
    else:
        print("Valitsemaasi toimintoa ei ole olemassa")
Nyt käyttäjää ei potkaista ohjelmasta ulos muunnoksen jälkeen:
Tämä ohjelma muuntaa yhdysvaltalaisia yksiköitä SI-yksiköiksi
Mahdolliset toiminnot:
(P)ituus
(M)assa
(T)ilavuus
(L)ämpotila
(Q)uittaa

Tee valintasi: p
Valitse pituusyksikkö seuraavien joukosta syöttämällä suluissa annettu lyhenne
Tuuma (in tai ")
Jalka (ft tai ')
Jaardi (yd)
Maili (mi)

Anna muutettava yksikkö: yd
Anna muutettava arvo: 12
12.000 yd on 10.973 m
Tee valintasi:
Päävalikkoon palauttaminen pituusmuunnoskyselystä on tosin sekin hieman ikävää, jos käyttäjä olisi halunnut tehdä toisen pituusmuunnoksen. Samanlainen
toistorakenne
olisi siis hyvä sisällyttää muihinkin
funktioihin
. On lisäksi päätettävä, kummasta
syötteestä
- arvosta vai yksiköstä - luetaan, haluaako käyttäjä palata takaisin. Yksikön valinta lienee parempi vaihtoehto, koska muuten tarvitaan muutoksia kysy_arvo-funktioon. Sovitaan, että tyhjäksi jätetty yksikkö tarkoittaa päävalikkoon palaamista. Täällä ei ole valmista
ehtorakennetta
johon lopetusehdon voisi sijoittaa, joten tehdään uusi.
def pituus():
    print("Valitse pituusyksikkö seuraavien joukosta syöttämällä suluissa annettu lyhenne")
    print("Jättämällä yksikön tyhjäksi palaat päävalikkoon")
    print("Tuuma (in tai \")")
    print("Jalka (ft tai ')")
    print("Jaardi (yd)")
    print("Maili (mi)")
    print()
    while True:
        yksikko = input("Anna muutettava yksikkö: ")
        if not yksikko:
            break
        arvo = kysy_arvo()
        try:
            kerroin = PITUUSKERTOIMET[yksikko]
        except KeyError:
            print("Valitsemaasi yksikköä ei voida muuntaa")
        else:
            print(f"{arvo:.3f} {yksikko} on {arvo * kerroin:.3f} m")
Huomattavaa on myös se, että silmukan päättävä break-lause on nostettu yksinkertaisen if not yksikko:-ehtolauseen kera arvon kyselyn yläpuolelle. Tällä yksinkertaisella kahden rivin kombinaatiolla silmukka päättyy heti, kun käyttäjä antaa tyhjän
syötteen.
.Osoitetaan toiminta:
Tämä ohjelma muuntaa yhdysvaltalaisia yksiköitä SI-yksiköiksi
Mahdolliset toiminnot:
(P)ituus
(M)assa
(T)ilavuus
(L)ämpotila
(Q)uittaa

Tee valintasi: p
Valitse pituusyksikkö seuraavien joukosta syöttämällä suluissa annettu lyhenne
Jättämällä yksikön tyhjäksi palaat päävalikkoon
Tuuma (in tai ")
Jalka (ft tai ')
Jaardi (yd)
Maili (mi)

Anna muutettava yksikkö: mi
Anna muutettava arvo: 10
10.000 mi on 16093.440 m
Anna muutettava yksikkö:
Tee valintasi: q
Tästä viimeistään ilmenee, että
break
(kuten myös return) päättää
silmukan
suorituksen välittömästi. Edes meneillään olevaa
kierrosta
ei suoriteta loppuun. Siksi siis arvo jää kysymättä. Alla vielä animaatio toisesta esimerkkiohjelmasta, jossa tyhjä
syöte
lopettaa
silmukan
.

Aasinlista

Käytetään edellistä esimerkkiä aasinsiltana seuraavaan aiheeseen. Aiemmin väläytettiin sivulauseessa ideaa, että muunnettavan arvon ja yksikön voisi kysyä yhdelläkin rivillä. Käyttö voisi silloin näyttää tältä:
Anna muutettava arvo ja yksikkö: 12 yd
12.000 yd on 10.973 m
Oppimistavoitteet: Tässä osiossa opitaan, mikä tarkalleen ottaen on lista ja miten se liittyy aiemmin käsiteltyihin tietotyyppeihin. Lisäksi opitaan tekemään listoja käyttäjän syöttämistä merkkijonoista sekä käsittelemään prosessissa syntyviä ongelmatapauksia.

Hiusten halkomista

Miten
merkkijonosta
otetaan irti kaksi erillistä asiaa? Ratkaisu riippuu käyttökontekstista, mutta ehdottomasti yleisin tapa on käyttää merkkijonon split-
metodia
. Kyseessä on metodi, joka jakaa merkkijonon osiin perustuen
argumentiksi
annettuun erottimeen. Erotin voi olla yksittäinen merkki tai merkkijono, ja se ei tule näkymään tuloksissa mukana. Esimerkiksi desimaaliluvun voisi jakaa kokonaisosaan ja desimaaliosaan käyttämällä erottimena pistettä:
In [1]: "12.54".split(".")
Out[1]: ['12', '54']
Tarvittaessa splitille voidaan myös määritellä
valinnaisella argumentilla
, että jakoja tehdään maksimissaan tietty määrä. Tätä ominaisuutta voidaan käyttää erityisesti
tiedostopäätteiden
erottamiseen
tiedoston nimestä
. Tyypillisiä skenaarioita, joissa pisteitä esiintyy tiedoston nimessä voivat olla musiikkitiedostojen nimet (esim. P.H.O.B.O.S. - 03 - Wisdoom.ogg) tai versionumeron sisältävät asennuspaketit (esim. Pythonin oma: python-3.8.1.exe). Tällöin käytetään tosin rsplit-metodia, joka toimii muuten samalla tavalla, mutta aloittaa splittaamisen alun sijaan lopusta.
In [1]: tiedosto = "aasinsilta_2.5.7.zip"
In [2]: tiedosto.rsplit(".", 1)
Out[2]: ['aasinsilta_2.5.7', 'zip']
Tässä esimerkissä siis tehdään vain yksi jako, ja koska käytetty
metodi
on rsplit, jaot tehdään alkaen lopusta. Näin saadaan erotettua tiedoston pääte nimestä itsestään. Metodin
palauttama
hakasuluilla ympäröity kokonaisuus tunnetaan myös
listana
(eng. list). Sellainen on nähty aiemminkin, sillä myös dir-funktio tuottaa listan:
In [1]: dir("")
Out[1]:
['__add__',
 '__class__',
 '__contains__',
 '__delattr__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__getnewargs__',
 '__gt__',
 '__hash__',
 '__init__',
 '__iter__',
 '__le__',
 '__len__',
 '__lt__',
 '__mod__',
 '__mul__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__rmod__',
 '__rmul__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'capitalize',
 'casefold',
 'center',
 'count',
 'encode',
 'endswith',
 'expandtabs',
 'find',
 'format',
 'format_map',
 'index',
 'isalnum',
 'isalpha',
 'isdecimal',
 'isdigit',
 'isidentifier',
 'islower',
 'isnumeric',
 'isprintable',
 'isspace',
 'istitle',
 'isupper',
 'join',
 'ljust',
 'lower',
 'lstrip',
 'maketrans',
 'partition',
 'replace',
 'rfind',
 'rindex',
 'rjust',
 'rpartition',
 'rsplit',
 'rstrip',
 'split',
 'splitlines',
 'startswith',
 'strip',
 'swapcase',
 'title',
 'translate',
 'upper',
 'zfill']
Listan
tunnistaa nimenomaan ympäröivistä hakasulkeista, samoin kuin
merkkijonon
tunnistaa lainausmerkeistä tai
sanakirjan
aaltosulkeista. Muutenkin listat ovat tunnetuista
tietotyypeistä
läheisintä sukua sekä merkkijonoille että sanakirjoille. Merkkijonon tapaan listat ovat
sekvenssityyppisiä
(ts. niissä on yksittäisiä asioita peräkkäin). Toisaalta taas sanakirjan tavoin listat ovat
muuntuvia
tietorakenteita
. Tarkoituksenamme oli tuottaa tämän näköistä toimintaa:
Anna muutettava arvo ja yksikkö: 12 yd
12.000 yd on 10.973 m
Voimme siis saada aikaan listan käyttäjän
syötteistä
split-
metodilla
(jakamalla merkkijono kahtia tyhjän kohdalta:
syote = input("Anna muutettava arvo ja yksikkö: ").split(" ")

Listojen lyhyt oppimäärä

Kuvalähde 3
Todella lyhyt oppimäärä listoista voidaan antaa kolmen sanan kuvauksella: järjestetty kokoelma arvoja. Jokainen näistä kolmesta sanasta kertoo yhden keskeisen asian listoista:
Kertauksena: sanakirja on (melkein) järjestämätön kokoelma arvoja - listan pääominaisuus niihin verrattuna on siis järjestyksen hallinta. Vaikka sanakirjassa on nykyään järjestys (lisäysjärjestys), sitä ei voi muuttaa. Syntaksin kannalta lista on hakasuluilla rajattu arvo, jonka sisällä olevat alkiot on erotettu toisistaan pilkuilla. Kuten funktioiden määrityksien ja kutsujen kanssa, myös listoja kirjoittaessa pilkkua seuraa aina välilyönti. Lista voi sisältää numeroita:
In [1]: tulokset = [12.54, 5.12, 38.14, 9.04]
tai vastaavasti
merkkijonoja
:
In [2]: jasenet = ["Haruna", "Tomomi", "Mami", "Rina"]
tai vaikka
funktioita
, muistutuksena siitä, että myös funktiot ovat
objekteja
:
In [3]: funktiot = [max, abs, min, round]
Sanakirjat
voi myös tunkea listaan, ja listan määrittelyn voi jakaa usealle riivlle kuten sanakirjankin:
In [4]: mittaukset = [
   ...:     {"arvo": 4.64, "yksikko": "in"},
   ...:     {"arvo": 13.54, "yksikko": "yd"}
   ...: ]
ja kuten mainittua, myös
listoja
voi laittaa listojen sisälle:
In [5]: [tulokset, jasenet, funktiot, mittaukset]
Out[5]:
[[12.54, 5.12, 38.14, 9.04],
 ['Haruna', 'Tomomi', 'Mami', 'Rina'],
 [<function max>, <function abs>, <function min>, <function round>],
 [{'arvo': 4.64, 'yksikko': 'in'}, {'arvo': 13.54, 'yksikko': 'yd'}]]
Viimeisestä esimerkistä näkyy myös miltä listan sisällä olevat listat näyttävät. Merkittävänä erona merkkijonoihin listan aloitus- ja lopetusmerkit ovat eri merkit (eli hakasulku auki ja hakasulku kiinni). Tämän ansiosta on mahdollista aloittaa uusi lista listan määrittelyn sisällä uudella avaavalla hakasulkeella. Tässä on tietenkin huomioitava, että kaikki aloitetut listat pitää muistaa myös lopettaa. Muutoin saadaan aikaan sama lopputulos, kuin jos unohtaa sulkea yhden tai useamman sulun rivillä, jossa kutsutaan sisäkkäin useita funktioita.

Viikon päivätehtävä

Listoja voi hyödyntää mm. siten, että niiden avulla voi antaa numeroille nimiä. Esimerkiksi laskettaessa viikonpäiviä saadaan tulokseksi tyypillisesti numeroita (esim. viikon 3. päivä), ja vastaava päivän nimi täytyy sitten etsiä jostain. Jos nimet ovat listassa, voidaan sieltä vain ottaa suoraan kolmas alkio ja saada siten vastaavan viikonpäivän nimi (keskiviikko).
Opittavat asiat:
Listan
, jossa on valmiiksi sisältöä, luominen.

Haettu vastaus:
Kirjoita vastaukseen koodirivi, jolla määritetään lista, josta löytyvät viikonpäivät
merkkijonoina
maanantaista sunnuntaihin (järjestyksessä), kaikki pienellä kirjoitettuna. Lista tulee lisäksi
sijoittaa
viikonpaivat-
muuttujaan
.
Kirjoita koodirivi laatikkoon.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Laskut listaan

Listaan voidaan laittaa kaikenlaista. Muuttujat listan alkioina ovat ihan arkipäivää, mutta samalla tavalla voidaan listaan tunkea vaikka operaation tai funktiokutsun tulos. Kaikissa tapauksissa listaan sijoittuu se lopullinen arvo, joka saadaan operaation tai funktiokutsun tuloksena.
Opittavat asiat: Tässä tehtävässä nähdään, että
listan
määrittelyssä
alkio
voidaan esittää
literaaliarvon
lisäksi myös
operaationa
,
funktiokutsuna
tai
metodikutsu
.

Alustus:
Kirjoita seuraava rivi
tulkkiin
sellaisenaan.
In [1]: [1 + 6, 6 - 4, max(4, 7), "aasi".upper()]

Haettu vastaus:
Vastaukseksi riittää, että kopioit ym. rivin tuloksen tulkista.
Kopioi saamasi lopputulos vastauslaatikkoon.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Kaapin paikka

Monet kohtaavat ohjelmointiuransa alkuvaiheella seuraavanlaisen pohdinnan: jos on olemassa
muuttujia
tyyliin luku_1, luku_2 jne., voisiko näitä kenties luoda dynaamisesti siten, että koodi generoisi itse lisää muuttujia aina luku_n:ään asti? Lyhyt vastaus kysymykseen on: EI (pitkä vastaus: teoriassa on, mutta vaatii tarpeettoman nokkelia temppuja, joilla voi helposti sotkea koodinsa). Vastaava toiminallisuus kylläkin onnistuu, kysymys on vain väärä. Oikea kysymys kuuluu, millaisella ratkaisulla voidaan ylläpitää tietoa ennaltamäärämättömästä määrästä arvoja. Vastaus tähän on tietenkin
lista
. Listaan voidaan varastoida N kpl
arvoja
, ja ne ovat siellä järjestyksessä. Vertaa:
In [1]: luku_1 = 13
In [2]: luku_2 = 6
In [3]: luku_3 = 24
tähän:
In [4]: luvut = [13, 6, 24]
Jälkimmäinen tapa on huomattavasti parempi, koska sitä käyttämällä tiettyyn arvoon (13, 6 tai 24) viittaava luku ei ole kiinni muuttujan nimessä. Miten tietty arvo saadaan sitten haettua listasta? Listassa
alkiot
ovat tietyssä järjestyksessä. Tätä järjestystä kuvaa alkion etäisyys listan alusta siten, että listan ensimmäisen alkion (esimerkissä arvo 13) etäisyys alusta on 0. Jos siis halutaan viitata eli osoittaa listan ensimmäiseen arvoon, käytetään viittaavana arvona numeroa 0. Tälle sijaintiin viittavalle numerolle on oma nimensä:
indeksi
(eng. index). Se toimii hyvin pitkälti samalla tavalla kuin
sanakirjan
avain
.
Itse viittaus tapahtuu seuraavanlaisella syntaksilla:
In [5]: luvut[0]
Out[5]: 13
In [6]: luvut[1]
Out[6]: 6
In [7]: luvut[2]
Out[7]: 24
Hakasulkeilla
listan
perässä on sama erityismerkitys kuin avainhaulla: sisältöön
osoittaminen
. Keskeinen ero sanakirjan avaimiin on se, että avaimet voivat olla mielivaltaisia
muuntumattomia
arvoja, mutta listan indeksit ovat aina numerot nollasta listan pituus miinus yhteen asti (ts. 0,...,N-1). Tämä ei itse asiassa ole pelkästään listojen ominaisuus, vaan toimii myös mm.
merkkijonoille
. Esimerkiksi jos halutaan tarkistella sanan alkukirjainta:
In [1]: sana = "aasisvengaa"
Out[1]: sana[0]
'a'

Luettelotietojen indeksointia

Opittavat asiat: Yksittäiseen
listan
alkioon
viittaaminen
indeksiosoituksella
.

Alustus:
Esimerkkiskenaariona toimikoon vaikkapa musiikintoisto-ohjelmassa oleellinen
tietorakenne
, jossa on yhdestä kappaleesta tietoja: tässä tapauksessa artistin nimi, albumin nimi, kappaleen nimi ja kesto. Esimerkkikappale voidaan siis tallentaa
tulkissa
muuttujaan
vaikkapa näin:
In [1]: kappale = ["Dirge", "Wings of Lead Over Dormant Seas", "Wings of Lead Over Dormant Seas", "60:00"]

Haettu vastaus:
Tarkoitus olisi nyt ottaa tästä yhdestä kappaleesta sen kesto erilliseen muuttujaan (nimeltään kesto). Kirjoita siis rivi, jossa listasta otetaan indeksiosoituksella kappaleen kesto, ja
sijoitetaan
se muuttujaan. Luonnollisesti vastauksessa tulee käyttää juuri määriteltyä kappale-muuttujaa.
Kirjoita koodirivi tähän.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Oli kyse sitten
listoista
tai
merkkijonoista
,
indeksien
on oltava kokonaislukuja.
Liukuluku
, jonka desimaaliosa on nolla ei kelpaa. Tämä on oikeastaan ensimmäinen kerta, kun int-funktiota saattaa tarvita liukulukujen muuttamiseen kokonaisluvuiksi. Esimerkkitapauksena voisi olla vaikka skenaario, jossa listasta poimitaan
alkioita
jollain matemagiikalla, jossa käytetään liukulukuja (kuten vaikka keskimmäinen indeksi listasta jonka pituus on pariton) Tällöin siis lopullinen tulos tulee muuttaa kokonaisluvuksi ennen kuin sillä voidaan poimia alkioita listasta.
Indeksiosoitusta
voidaan nyt hyödyntää jatkamalla tämän toiminnallisuuden toteuttamista:
Anna muutettava arvo ja yksikkö: 12 yd
12.000 yd on 10.973 m
Käyttämällä indeksillä osoittamista voidaan split-
metodin
tuottamasta listasta ottaa sen alkiot erikseen käsiteltäväksi, vaikkapa
tallentamalla
ne uusiin
muuttujiin
.
syote = input("Anna muutettava arvo ja yksikkö: ").split(" ")
arvo = syote[0]
yksikko = syote[1]

Sherlock de Bug kohtaa arkkivihollisensa

Yksi hyvin yleinen arkkivihollinen käyttäjän syötteiden käsittelyssä on unohtaa, että syöte palautetaan aina merkkijonona. Joskus tämä virhe voi kulkeutua koodissa pitkällekin ennen kuin ohjelma lopulta hajoaa.
Opittavat asiat: Mikä
poikkeus
syntyy, kun
syötteestä
luettuja lukuarvoja koitetaan käyttää laskutoimituksissa sellaisenaan. Mitä syötteenkäsittelyssä tulee muuttaa, jotta tältä ongelmalta vältytään.

Alustus:
Loihditaan
tulkkiin
samat rivit kuin yllä, eli:
In [1]: syote = input("Anna muutettava arvo ja yksikkö: ").split(" ")
Anna muutettava arvo ja yksikkö: 12 m
In [2]: arvo = syote[0]
Kokeile nyt suorittaa arvo-muuttujaa käyttämällä jokin laskuoperaatio, joka ei ole kertolasku (vaikka vähentää siitä 1).

Haettu vastaus:
Laskuoperaation pitäisi mennä pieleen, ja siitä syntyy tietty poikkeus. Vastaukseen halutaan tämän poikkeuksen nimi. Lisäksi ongelma pitäisi ratkaista. Kirjoita siis vastaukseen myös esimerkin toinen rivi uudestaan siten, että arvo-muuttujaa voidaan käyttää liukulukuna laskutoimituksissa.
Poikkeuksen nimi ensimmäiselle riville, toiselle korjattu muuttujaan sijoitus.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Sherlock de Bug ja kadonneen indeksin arvoitus

Sen lisäksi, että ohjelmoija on oma arkkivihollisensa syötteenkäsittelyssä, käyttäjä tulee heti toisena. Tässäkin esimerkissä oletetaan, että käyttäjä osaa antaa arvon sekä yksikön, mutta mitä käykään kun käyttäjä ei osaa?
Opittavat asiat: Mikä toinen yleinen
poikkeus
syntyy, kun luotetaan liiaksi siihen, että käyttäjä osaa antaa
syötteen
oikein.

Alustus:
Toimitaan samoin kuin edellisessä tehtävässä, mutta otetaan myös esimerkin kolmas rivi mukaan. Lisäksi simuloidaan käyttäjää, joka syöttää pelkän lukuarvon ilman yksikköä.
In [1]: syote = input("Anna muutettava arvo ja yksikkö: ").split(" ")
Anna muutettava arvo ja yksikkö: 12
In [2]: arvo = syote[0]
In [3]: yksikko = syote[1]

Haettu vastaus:
Yksi näistä riveistä synnyttää poikkeuksen. Vastaukseen haetaan kahta riviä: tämän poikkeuksen nimeä, sekä sitä riviä, josta poikkeus syntyi. Kopioi rivi vastaukseen.
Ensimmäiselle riville poikkeuksen nimi, toiselle aiheuttava rivi.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Esitellään vielä toinen tapa ottaa splitin tulokset
muuttujiin
talteen:
arvo, yksikko = input("Anna muutettava arvo ja yksikkö: ").split(" ")
Tämä tapa toimii tosin pääasiassa silloin, kun kaikki arvot halutaan ottaa talteen
merkkijonoina
. Nyt joudutaan siis joka tapauksessa vielä ylimääräisellä rivillä muuttamaan arvo merkkijonosta
liukuluvuksi
. Tällä kertaa saadaan myös aikaan eri
poikkeus
, jos käyttäjän
syötteestä
ei saada split-
metodilla
oikean pituista
listaa
ulos:
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-1-21b56e44815b> in <module>()
----> 1 arvo, yksikko = input("Anna muutettava arvo ja yksikkö: ").split(" ")

ValueError: not enough values to unpack (expected 2, got 1)
Kun merkkijonoja jaetaan osiin, tuleekin muistaa aina tarkistaa, että jako tuottaa oikean määrän tuloksia. Jos siis käytettäisiin tätä tapaa kysyä sekä arvo että yksikkö, kyselyfunktioon pitäisi tehdä muutoksia. Tämä vaatii uuden exceptin lisäämistä try-rakenteeseen. Tässä ei ole juurikaan eroa siihen, miten
ehtorakenteeseen
voidaan lisätä mielivaltainen määrä elif-lauseita. Poikkeuksen käsittelyssä voi yhtälailla olla mielivaltainen määrä except-lauseita, ja kuten ehtorakenteen haaroista, myös niistä suoritetaan ensimmäinen johon koodin tuottama poikkeus sopii. Tämän lisäksi
funktion
tulee tietenkin
palauttaa
nyt kaksi arvoa yhden sijaan.
def kysy_muutettava():
    while True:
        try:
            muutettava = input("Anna muutettava arvo ja yksikkö: ").split(" ")
            arvo = float(muutettava[0])
            yksikko = muutettava[1]
        except ValueError:
            print("Arvon tulee olla pelkkä luku")
        except IndexError:
            print("Syötteessä tulee olla arvo ja yksikkö välilyönnillä toisistaan erotettuna")
        else:
            return arvo, yksikko
Kahden paluuarvon vuoksi itse
funktiokutsuakin
täytyy muokata. Samalla muutetaan funktion nimi hieman kuvaavammaksi. Funktiokutsu näyttäisi nyt muualla koodissa tältä:
arvo, yksikko = kysy_muutettava()
Emme kuitenkaan ota tätä käyttöön, koska se rikkoisi aikaisemmin kehitetyn päävalikkoon palaamisen (asian voisi toki korjata useammalla tavalla). Tämä jääköön esimerkiksi siitä, miten tyypillisesti täytyy käsitellä poikkeuksia, kun käyttäjän syötteestä halutaan ottaa split-metodilla useita arvoja kerralla.

Kokoelmateos listoista

Seuraavaksi tavoitteena on tehdä komentoriviohjelma, joka soveltuu kokoelmien ylläpitämiseen. Esimerkin ohjelma on tarkoitettu levykokoelman käsittelyyn, mutta se on helposti muokattavissa johonkin muuhun tarkoitukseen. Ohjelman perusominaisuuksia ovat levyjen lisääminen, poistaminen ja tietojen muokkaaminen.
Oppimistavoitteet: Tässä osiossa opitaan lisää listoista ja erityisesti, miten niihin lisätään tavaraa. Opimme myös, että listat ovat muuntuvia, ja jopa senkin, mitä tämä tarkoittaa käytännössä. Uutena asiana tulevat myös kommenttirivit, joita voi käyttää koodin selkeyttämiseen.

Välikommentti

Tilanteissa, joissa oikeaa koodia ei ole vielä käytössä, on hyvä tehdä korvaavaa koodia, joka toimii muun koodin näkökulmasta samalla tavalla. Koodiin voitaisiin siis laittaa jo valmiiksi
funktiot
lataa_kokoelma ja tallenna_kokoelma. Jälkimmäinen voidaan jättää tyhjäksi (käyttäen pass-avainsanaa). Ensimmäisessä sen sijaan voidaan luoda kokoelmaa esittävä
lista
, johon on sijoitettu muutamia levyjä malliksi. Näin päästään kokeilemaan ohjelman ominaisuuksia, vaikka oikeaa dataa ei olekaan saatavilla.
Sovitaan kokoelmaan laitettavaksi perustietoja viiteen eri kenttään: artistin nimi, levyn nimi, kappaleiden määrä, kesto ja julkaisuvuosi. Koska kentillä on selkeät nimet, paras tapa esittää yksittäinen levy on
sanakirja
, joka näyttää esim. tältä:
{
    "artisti": "Monolithe",
    "albumi": "Nebula Septem",
    "kpl_n": 7,
    "kesto": "49:00",
    "julkaisuvuosi": 2018
}
Kuvalähde 4
Ennen kuin meillä on yhtään levyä kokoelmassa, sovittujen avainten muistamisen avuksi voidaan ottaa
kommenttirivit
. Kommentit ovat rivejä, jotka
Python
ohittaa koodia suorittaessa. Niille voi siis kirjoittaa lisätietoa koodin lukijalle, eli esimerkiksi itselleen. Kommenteilla voi selittää vaikean näköisiä kohtia ohjelman toiminnassa. Niitä voi myös käyttää suunnittelussa: toteuttamattomiin kohtiin koodissa voi kirjoittaa lyhyen kuvauksen, mitä ko. kohdan on tarkoitus tehdä kun se on valmis. Tällä tavalla, jos pidemmässä projektissa ohittaa jonkin yksityiskohdan alkuvaiheessa, pystyy vielä lopussakin muistamaan, mitä siihen oli alunperin tarkoitus tehdä. Kommenteilla voi myös luoda itselleen muistutuksia siitä, mitä
tietorakenteen
olisi tarkoitus sisältää:
def lataa_kokoelma():

    # avaimet:
    # artisti, albumi, kpl_n, kesto, julkaisuvuosi
    kokoelma = []
    return kokoelma
Rivit, jotka alkavat #-merkillä, ovat kommenttirivejä. Kun Python kohtaa tämän merkin
merkkijonon
ulkopuolella, se lopettaa rivin tulkitsemisen siihen ja jatkaa seuraavalle. Ylläolevassa koodissa on siis ainoastaan kolme suoritettavaa koodiriviä funktion sisällä: funktion määrittelyrivi; rivi, joka luo uuden (tyhjän) listan; ja rivi, joka
palauttaa
sen.
Kommenteilla
on käyttönsä myös ohjelman virheitä ratkoessa. Laittamalla kommenttimerkin rivin eteen voi nimittäin jättää rivin suorituksen pois ilman, että sitä tarvitsee suorilta käsin poistaa (jos vaikka myöhemmin osoittautuu, että rivi olikin oikein). Tällä tavalla voi myös tilapäisesti ohittaa virheellisen rivin tarkistaakseen toimiiko loput ohjemasta oikein.
Kommenttien sukulaisia ovat
dokumenttimerkkijonot
(docstring). Näiden käyttö on hieman standardoidumpaa kuin kommenttien. Dokumenttimerkkijono liitetään tyypillisesti
funktioon
. Se on itse asiassa juuri se
merkkijono
, jonka näet help-funktiolla
tulkissa
. Siitä tulee vähintään ilmetä, mitä funktio tekee, millaisia
argumentteja
sille pitää ja/tai voi antaa sekä mitä se
palauttaa
. Dokumenttimerkkijono merkitään tyypillisesti kolminkertaisilla lainausmerkeillä ja sen tulee sijaita välittömästi funktion määrittelyrivin alla ennen ensimmäistäkään varsinaista koodiriviä.
def lataa_kokoelma():
    """
    Luo testikokoelman. Palauttaa listan, joka sisältää viiden avain-arvo-parin
    sanakirjoja.
    Sanakirjan avaimet vastaavat seuraavia tietoja:
    "artisti" - artisti nimi
    "albumi" - levyn nimi
    "kpl_n" - kappaleiden määrä
    "kesto" - kesto
    "julkaisuvuosi" - julkaisuvuosi
    """

    # avaimet:
    # artisti, albumi, kpl_n, kesto, julkaisuvuosi
    kokoelma = []
    return kokoelma
Jos kirjoitetaan tämän alle
pääohjelmaan
rivi help(lataa_kokoelma) nähdään seuraavanlainen tuloste:
Help on function lataa_kokoelma in module __main__:

lataa_kokoelma()
    Luo testikokoelman. Palauttaa listan, joka sisältää viiden avain-arvo-parin
    sanakirjoja.
    Sanakirjan avaimet vastaavat seuraavia tietoja:
    "artisti" - artisti nimi
    "albumi" - levyn nimi
    "kpl_n" - kappaleiden määrä
    "kesto" - kesto
    "julkaisuvuosi" - julkaisuvuosi
Tämä näyttää jo varsin tutulta.
Dokumenttimerkkijonojen
käyttö on äärimmäisen hyvä tapa viimeistään, kun koodia saattaa katsoa joku muukin kuin sinä – mukaanlukien tulevaisuuden sinä, joka ei välttämättä muista, mitä koodia kirjoittaessa on päässäsi liikkunut. Tällä kurssilla tämä pätee erityisesti lopputyöhön, koska niitä tarkistavat assistentit ihan manuaalisesti koodia lukemalla. Isommissa projekteissa dokumenttimerkkijonoja voi hyödyntää myös erillisten työkalujen kanssa. Yksi tällainen on Sphinx, jonka avulla oikealla tavalla dokumentoidusta koodista voi luoda näppärät manuaalisivut koodille.
Lisätään koodiimme vielä
tynkäfunktio
tallenna_kokoelma ja laitetaan joitain levyjä lataa_kokoelma-funktion
listaan
seuraavia vaiheita varten. Alla on esitetty vain osa testikokoelman määrityksestä, koska sanakirjoja sisältävän listan kirjoitus menee jo aika pitkäksi... kommentin kentistä voi jättää pois, koska sama informaatio löytyy jo dokumenttimerkkijonosta.
def lataa_kokoelma():
    """
    Luo testikokoelman. Palauttaa listan, joka sisältää viiden avain-arvo-parin
    sanakirjoja.
    Sanakirjan avaimet vastaavat seuraavia tietoja:
    "artisti" - artisti nimi
    "albumi" - levyn nimi
    "kpl_n" - kappaleiden määrä
    "kesto" - kesto
    "julkaisuvuosi" - julkaisuvuosi
    """

    kokoelma = [
        {
            "artisti": "Alcest",
            "albumi": "Kodama",
            "kpl_n": 6,
            "kesto": "42:15",
            "julkaisuvuosi": 2016
        },
        {
            "artisti": "Canaan",
            "albumi": "A Calling to Weakness",
            "kpl_n": 17,
            "kesto": "1:11:17",
            "julkaisuvuosi": 2002
        },
        {
            "artisti": "Deftones",
            "albumi": "Gore",
            "kpl_n": 11,
            "kesto": "48:13",
            "julkaisuvuosi": 2016
        },
        # katkaistaan tästä, koko esimerkin koodissa määritelty 8 lisää
    ]
    return kokoelma

def tallenna_kokoelma(kokoelma):
    """
    Tallentaa kokoelman, joskus tulevaisuudessa.
    """

    pass
Luodaan seuraavaksi alustava
pääohjelma
, josta voi valita ohjelman perustoiminnot, sekä muutama uusi
tynkäfunktio
:
def lisaa(kokoelma):
    pass

def poista(kokoelma):
    pass

def tulosta(kokoelma):
    pass

kokoelma = lataa_kokoelma()
print("Tämä ohjelma ylläpitää levykokoelmaa. Voit valita seuraavista toiminnoista:")
print("(L)isää uusia levyjä")
print("(P)oista levyjä")
print("(T)ulosta kokoelma")
print("(Q)uittaa")
while True:
    valinta = input("Tee valintasi: ").strip().lower()
    if valinta == "l":
        lisaa(kokoelma)
    elif valinta == "p":
        poista(kokoelma)
    elif valinta == "t":
        tulosta(kokoelma)
    elif valinta == "q":
        break
    else:
        print("Valitsemaasi toimintoa ei ole olemassa")
tallenna_kokoelma(kokoelma)
Kokoelma ladataan ohjelman alussa ja (ainakin teoriassa, jos funktio tekisi jotain) tallennetaan lopussa. Tiedostoon on myös lisätty kustakin pääohjelmassa mainitusta funktiosta tynkä, jotta koodin voi suorittaa (jätetään dokumenttimerkkijonot pois, koska funktiot tehdään kohta).

Mutanttilistat kasvavat silmissä

Sanakirjasta
poiketen
Listaan
ei voi lisätä
arvoja
pelkästään määrittelemällä uuden
indeksin
ja sijoittamalla siihen jotain. Alla esitetty ensin avain-arvo-parin lisäys sanakirjaan, ja sen jälkeen näytetty mitä tapahtuu jos samaa koittaa listalle:
In [1]: sk = {"a": 1, "b": 2, "c": 3}
In [2]: sk["d"] = 4
In [3]: sk
Out[3]: {'a': 1, 'b': 2, 'c': 3, 'd': 4}
In [4]: numerot = [213, 12, 45]

In [5]: numerot[3] = 53
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-5-f353565de7fa> in <module>()
----> 1 numerot[3] = 53

IndexError: list assignment index out of range
Mikä mahtaa olla se hyväksytty tapa? Hyvin lyhyesti esitettynä listaan lisätään
alkioita
append-nimisellä
metodilla
, joka lisää uuden alkion listan loppuun. Lyhyestä selityksestä lyhyt esimerkki:
In [1]: numerot = [213, 12, 45]
In [2]: numerot.append(34)
In [3]: print(numerot)
[213, 12, 45, 34]
Ero tulee pitkälti siitä, että listaan lisätyt arvot menevät indeksien mukaisessa järjestyksessä, joten lisätessä ei tarvitse tietää monenneksiko alkioksi uusi arvo päätyy. Sen sijaan sanakirjassa avaimet ovat mielivaltaisia, joten avain johon arvo sidotaan pitää määrittää erikseen - ts. Python ei pysty päättelemään mikä avaimen tulisi olla. Samaa sen sijaan on se, että lista on
muuntuva
tietotyyppi, joten sanakirjan tavoin tässä prosessissa ei synny uutta kopioita. Samaten jos useampi muuttuja viittaa samaan listaan, lisätty alkio ilmestyy niihin kaikkiin. Tämä on myös ensimmäinen kerta kurssilla kun luodaan uusi viittaus ilman
sijoitusoperaattoria
.

Sherlock de Bug ja kadonneiden todisteiden mysteeri

Merkkijonoihin tavaraa lisättäessä tulos piti aina tallentaa takaisin (samaan) muuttujaan. Pitäisiköhän näiden listojen kanssa kuitenkin tehdä ihan varmuuden vuoksi samalla tavalla?
Opittavat asiat: Mitä tapahtuu kun append-
metodikutsun
paluuarvo
sijoitetaan
muuttujaan
.

Alustus:
Käydään
tulkissa
läpi seuraavanlainen prosessi. Ennen kokeilua mieti myös, mitä tämä koodi voisi tulostaa.
In [1]: todisteet = ["sormenjälki", "kirjeveitsi", "Ihaa-pehmolelu"]
In [2]: todisteet = todisteet.append("imgur-käyttäjätunnus")
In [3]: print(todisteet)

Haettu vastaus:
Vastaukseen riittää kopioida printin tulostama rivi. Jos olet hämmentynyt tuloksesta, kannattaa seuraava tekstiosio lukea erityisen tarkasti.
Laita vastaukseesi tulkista saatu tulostus.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Kuvalähde 5
Vilkaistaan help-funktiolla append-metodia:
append(...) method of builtins.list instance
    L.append(object) -> None -- append object to end
Muistetaan, että näissä tyypillisesti nuolen oikealla puolella on
funktion
tai
metodin
palauttaman
arvon
tyyppi
. Palautettava arvo on tässä None, joka on siitä erityinen, että se tarkoittaa käytännössä "ei mitään". Kyseessä on siis tyhjä
objekti
, joka on yhtä suuri ainoastaan itsensä kanssa ja jonka
totuusarvo
on sama kuin False. Funktiot ja metodit, joissa ei ole returnia lainkaan, tai joissa return-rivillä ei ole yhtään palautettavaa arvoa, palauttavat aina Nonen.
Koska
listat
ovat luonteeltaan
muuntuvia
, lisäys käyttäytyy samalla tavalla kuin sanakirjojen tapauksessa. Animaatio havainnollistaa tätä ilmiötä listojen suhteen.
On olemassa myös tapa lisätä
listaan
asioita siten, että tuloksena syntyy uusi lista. +-operaattorilla kaksi listaa voidaan liittää yhteen:
In [1]: numerot_1 = [1, 2, 3]
In [2]: numerot_2 = numerot_1
In [3]: numerot_2 = numerot_2 + [4]
In [4]: print(numerot_1, numerot_2)
[1, 2, 3] [1, 2, 3, 4]
Tätä näkee tehtävän erittäin harvoin, koska listojen turha kopiointi on kaikin puolin raskasta ja yleensä on huomattavasti käytännöllisempää, että kaikki ohjelman osat käsittelevät samaa listaa. Näin on meidän levykatalogiohjelmassammekin. Kun lisaa-
funktio
lisää kokoelmaan levyjä, lisätyt levyt näkyvät niin
pääohjelmassa
kuin kaikkialla muuallakin, eikä tarvitse huolehtia siitä, että vahingossa käytettäisiin jossain kohdassa vanhentunutta kopiota listasta. Tästä syystä myöskään lisaa-funktion ei tarvitse
palauttaa
listaa, koska se käsittelee sitä yhtä ja ainoaa muistissa olevaa listaa, joka on alunperin ladattu lataa_kokoelma-funktiossa.

Nollat tauluun

Alkioiden lisääminen listoihin suorituksen aikana on hyvin yleistä ohjelmoinnissa. Kuvitellaan vaikkapa sovellus, joka käsittelee mittaustuloksia ja kokoaa ne listaan. Virhearvojen kohdalla on sovittu, että listaan lisätään tuloksen sijaan nolla. Harjoittelemme tässä tehtävässä tuon nollan lisäämistä olemassaolevaan listaan.
Opittavat asiat: Painaa mieleen, miten
listoihin
tulee lisätä
alkioita
oikeaoppisesti.

Alustus:
Määritellään listamuuttuja, joka sisältää mittaustuloksia:
In [1]: mittaukset = [12.3, 44.51, 133.7]

Haettu vastaus:
Tehtäväsi on kirjoittaa yksi koodirivi, joka lisää tähän listaan arvon 0.0. Lisäys täytyy tehdä siten, että listasta ei synny ylimääräistä kopiota.
Kirjoita vastauksesi alle.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Näillä tiedoilla pystymme toteuttamaan lisaa-funktion sisuskalut.
def lisaa(kokoelma):
    print("Täytä lisättävän levyn tiedot. Jätä levyn nimi tyhjäksi lopettaaksesi")
    while True:
        levy = input("Levyn nimi: ")
        if not levy:
            break

        artisti = input("Artistin nimi: ")
        kpl_n = kysy_luku("Kappaleiden lukumäärä: ")
        kesto = kysy_aika("Kesto: ")
        vuosi = kysy_luku("Julkaisuvuosi: ")
        kokoelma.append({
            "artisti": artisti,
            "albumi": levy,
            "kpl_n": kpl_n,
            "kesto": kesto,
            "julkaisuvuosi": vuosi
        })
        print("Levy lisätty")
Tämä
funktio
lisää levyjä, kunnes käyttäjä
syöttää
tyhjän levyn nimen. Uuden opitun asian soveltaminen näkyy usealle riville jaetussa append-
metodikutsussa
, jossa kokoelma-
listaan
lisätään uutta levyä kuvaava sanakirja. Huomaa myös returnin puute funktiossa. Sitä ei tarvita lainkaan, koska funktio muuttaa listaa, joka on olemassa samanlaisena kaikkialla missä siihen viitataan. Koodissa esiintyy myös kaksi uutta funktiota. Näistä kysy_luku on hyvin läheistä sukua aiemmin nähdylle kysy_arvo-funktiolle:
def kysy_luku(kysymys):
    while True:
        try:
            luku = int(input(kysymys))
        except ValueError:
            print("Arvon tulee olla kokonaisluku")
        else:
            return luku
Eroja aiempaan on kaksi: ensinnäkin, koska tätä käytetään kappaleiden määrän ja vuosiluvun kysymiseen, on järkevämpää hyväksyä ainoastaan kokonaislukuja. Toiseksi olemme korvanneet input-funktion
argumenttina
olleen kysymysmerkkijonon
muuttujalla
. Näin toimimalla voidaan samaa funktiota käyttää kaikkiin kysymyksiin, joissa halutaan käyttäjältä kokonaisluku. Kysymys tulee nyt funktiokutsun argumenttina. Tämä on erittäinen käytännöllinen temppu mihin tahansa ohjelmaan, jossa kysytään useita kertoja samanlaisia
syötteitä
(kuten tässä kysytään useaan kertaan kokonaislukuja).
Poikkeuksia
valvova try-rakenne tarvitsee kirjoittaa vain kerran, mutta kuitenkin käyttäjälle annettavaa ohjetta voidaan helposti vaihtaa kutakin syötettä paremmin kuvaavaksi vaihtamalla funktion argumenttia.
Sen sijaan kysy_aika-funktio jätetään toistaiseksi tyngäksi. Aikasyötteen oikeamuotoisuuden tarkistusta mietitään myöhemmin.
def kysy_aika(kysymys):
    return input(kysymys)
Nyt funktio toimii kivan näköisesti:
Tämä ohjelma ylläpitää levykokoelmaa. Voit valita seuraavista toiminnoista:
(L)isää uusia levyjä
(P)oista levyjä
(T)ulosta kokoelma
(Q)uittaa
Tee valintasi: l
Täytä lisättävän levyn tiedot. Jätä levyn nimi tyhjäksi lopettaaksesi
Levyn nimi: Lead and Aether
Artistin nimi: Skepticism
Kappaleiden lukumäärä: 12.5
Arvon tulee olla kokonaisluku
Kappaleiden lukumäärä: 6
Kesto: 47:49
Julkaisuvuosi: 1997
Levy lisätty
Levyn nimi:
Tee valintasi: q

Mittaustilaus

Alkioiden lisääminen listoihin tapahtuu usein yksi kerrallaan juuri opitun appendin avulla. Joissain tapauksissa kuitenkin halutaan yhden alkion sijaan lisätä useita alkioita kerralla, esimerkiksi toisen listan sisältö. Tässä tapauksessa appendia ei voi käyttää, koska se lisäisi toisen listan yhdeksi alkioksi aiemman sisälle, eli listaksi listan sisälle... Mikä siis neuvoksi?
Opittavat asiat: Tapa, jolla voidaan lisätä kerralla useita
alkioita
olemassaolevaan
listaan
.

Alustus:
Olkoon meillä jälleen kuvitteellinen lista vanhoja mittauksia ja lisäksi toinen lista, jossa on sarja tuoreita mittauksia, jotka pitäisi lisätä muiden joukkoon.
In [1]: mittaukset = [12.3, 44.51, 133.7, 0.0]
In [2]: sarja = [45.2, 15.2, 7.89]
Avuksi kannattaa myös etsiä listojen dokumentaatio. Yksi tapa nähdä se on käyttää tulkin help-toimintoa:
In [3]: help([])

Haettu vastaus:
Tehtäväsi on siis dokumentaatiota apuna käyttäen selvittää, millä listan metodilla voidaan lisätä useita alkioita kerralla listan loppuun. Dokumentaatiossa saatat kohdata sanan iterable. Tämä on yleisnimitys kaikille
sekvenssityyppisille
objekteille
, joihin siis myös listat kuuluvat.
Varsinaisen vastauksen tulisi olla yksi koodirivi, joka lisää sarja-muuttujan sisältämän listan alkiot mittaukset-listan perään siten, että lopputulos näyttää tältä:
In [5]: mittaukset
[12.3, 44.51, 133.7, 0.0, 45.2, 15.2, 7.89]
Huomaa, että listojen liittämisoperaatiossa +-
operaattorilla
syntyy uusi lista, joten se ei kelpaa vastaukseksi!
Laita vastaukseen koodirivi, joka tekee tämän lisäyksen.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Armotonta pyöritystä

Seuraavaksi listat saavat kaverikseen uudenlaisia silmukoita, joiden avulla niitä voidaan käydään nätisti läpi. Tavoitteena on saada toteutettua yksi uusi toiminto: listojen tulostaminen.
Oppimistavoitteet: Tästä osiosta on tarkoitus oppia mitä ovat for-silmukat, ja miten ne liittyvät listoihin. Tutustumme myös uuteen merkkijonometodiin, jolla saadaan uskomaton määrä kauneutta tulostuksiin.

Läpijuoksu

Koska tulostaminen esittelee
for-silmukat
vähän lempeämmin, aloitamme siitä. Tarkoitus on siis täyttää tulosta-
funktio
aiemmasta ohjelmastamme. Ensimmäinen kokeiltava asia olisi tietenkin tulostaa
lista
ihan vain print-funktiolla.
def tulosta(kokoelma):
    print(kokoelma)
Jos tämä olisi näin helppoa, asialle tuskin olisi tarvinnut omistaa omaa väliotsikkoaan. Ja eihän se olekaan, koska lopputulos ei ole erityisen luettava (rivit katkottu 80 merkin kohdalta käsin):
Tämä ohjelma ylläpitää levykokoelmaa. Voit valita seuraavista toiminnoista:
(L)isää uusia levyjä
(M)uokkaa levyjä
(P)oista levyjä
(J)ärjestä kokoelma
(T)ulosta kokoelma
(Q)uittaa
Tee valintasi: t
[{'artisti': 'Alcest', 'albumi': 'Kodama', 'kpl_n': 6, 'kesto': '0:42:15', 'julk
aisuvuosi': 2016}, {'artisti': 'Canaan', 'albumi': 'A Calling to Weakness', 'kpl
_n': 17, 'kesto': '1:11:17', 'julkaisuvuosi': 2002}, {'artisti': 'Deftones', 'al
bumi': 'Gore', 'kpl_n': 11, 'kesto': '0:48:13', 'julkaisuvuosi': 2016}, {'artist
i': 'Funeralium', 'albumi': 'Deceived Idealism', 'kpl_n': 6, 'kesto': '1:28:22',
 'julkaisuvuosi': 2013}, {'artisti': 'IU', 'albumi': 'Modern Times', 'kpl_n': 13
, 'kesto': '47:14', 'julkaisuvuosi': 2013}, {'artisti': 'Mono', 'albumi': 'You A
re There', 'kpl_n': 6, 'kesto': '1:00:01', 'julkaisuvuosi': 2006}, {'artisti': '
Panopticon', 'albumi': 'Roads to the North', 'kpl_n': 8, 'kesto': '1:11:07', 'ju
lkaisuvuosi': 2014}, {'artisti': 'PassCode', 'albumi': 'Clarity', 'kpl_n': 13, '
kesto': '0:49:27', 'julkaisuvuosi': 2019}, {'artisti': 'Scandal', 'albumi': 'Hel
lo World', 'kpl_n': 13, 'kesto': '53:22', 'julkaisuvuosi': 2014}, {'artisti': 'S
lipknot', 'albumi': 'Iowa', 'kpl_n': 14, 'kesto': '1:06:24', 'julkaisuvuosi': 20
01}, {'artisti': 'Wolves in the Throne Room', 'albumi': 'Thrice Woven', 'kpl_n':
 5, 'kesto': '42:19', 'julkaisuvuosi': 2017}]
ja reaktio:
Kuvalähde 6
Toivottavaa olisikin, että tulostus olisi enemmänkin jotain tämän näköistä:
1.  Alcest - Kodama (2016) [6] [42:15]
2.  Canaan - A Calling to Weakness (2002) [17] [1:11:17]
3.  Deftones - Gore (2016) [11] [48:13]
4.  Funeralium - Deceived Idealism (2013) [6] [1:28:22]
5.  IU - Modern Times (2013) [13] [47:14]
6.  Mono - You Are There (2006) [6] [1:00:01]
7.  Panopticon - Roads to the North (2014) [8] [1:11:07]
8.  PassCode - Clarity (2019) [13] [49:27]
9.  Scandal - Hello World (2014) [13] [53:22]
10. Slipknot - Iowa (2001) [14] [1:06:24]
11. Wolves in the Throne Room - Thrice Woven (2017) [5] [42:19]
Eli jokainen levy omalla rivillään ilman ylimääräisiä hakasulkuja, aaltosulkuja tai lainausmerkkejä. Koska yksi print tuottaa perinteisesti yhden tulosterivin, voidaan ajatella, että on tarpeen
kutsua
print-
funktiota
jokaiselle
listan
alkiolle
erikseen. Aiemmin tässä materiaalissa opittiin, että toisto tehdään tyypillisesti
toistorakenteilla
eli silmukoilla. Opimme kuitenkin vain
while-silmukan
, jota tulee käyttää silloin, kun toistojen määrää ei voida määrittää ennen toiston aloittamista. Tässä tapauksessa toistojen määrä kuitenkin voidaan määrittää, sillä ohjelma voi laskea tulostettavien levyjen määrän ennen toistorakenteen aloittamista.
Pythonissa on
for-silmukka
on työkalu tällaista tapausta varten. Se on tarkoitettu erityisesti listojen ja muiden
sekvenssien
läpikäyntiin. Näille löytyy yhteisnimitys iteroitava (iterable), joka viittaa juuri siihen, että ne ovat
objekteja
, joita voi käydä läpi. Listojen lisäksi näitä ovat
merkkijonot
ja myöhemmin esiteltävät
monikot
, sekä erinäiset erikoisobjektit, kuten
generaattorit
ja
enumerate-objektit
.
Pythonin for-silmukka suorittaa sisällään olevat komennot jokaista läpikäytävää
alkiota
kohden. Usein sitä käytetään toistamaan jokin operaatio tai operaatioiden sarja jokaiselle
listan
alkiolle. Se soveltuu siis hyvin siihen, että tulostetaan jokainen listan alkio print-funktiolla. Ennen kuin hypätään suoraan lopputulokseen, tutkitaan for-silmukan yksityiskohtia. Aloitetaan mahdollisimman yksinkertaisesta esimerkistä tulkissa:
In [1]: elukoita = ["koira", "kissa", "orava", "mursu", "aasi", "laama"]
In [2]: for elain in elukoita:
   ...:     print(elain)
   ...:
koira
kissa
orava
mursu
aasi
laama
Tämä ainakin osoittaa todeksi väittämän, että for-silmukka suorittaa sisältämänsä operaation jokaisen läpikäytävän listan alkion kohdalla. Varsinainen silmukka määritellään seuraavasti, aloittamalla rivi
avainsanalla
:
for elain in elukoita:
Itse for-avainsanan lisäksi myös in-
operaattori
on kiinteä osa for-silmukan määrittelyä. Tämä luetaan: "jokaiselle elain sarjassa elukoita". Aivan kuten
funktiossa
on nimetyt
parametrit
, tässä esimerkissä on elain-
muuttuja
, jota kutsuttakoon
silmukkamuuttujaksi
, edustaa silmukan sisällä listan kulloinkin käsittelyssä olevaa
alkiota
. Se siis saa
arvot
"koira", "kissa", "orava", "mursu", "aasi" ja "laama" tässä järjestyksessä silmukan suorituksen aikana. Arvo vaihtuu jokaisella kierroksella.
Kuvalähde 7
Animaation lopussa myös ilmenee, että
silmukkamuuttuja
ei lakkaa olemasta silmukan päätyttyä. Täten se eroaa selkeästi
funktion
parametrista
, joka on ainoastaan olemassa funktion sisällä. Tälle ei varsinaisesti ole mitään yleisiä käyttötarkoituksia. Asia on sen sijaan hyvä pitää mielessä, koska muuten saattaa tapahtua yllätyksiä. Varmuuden vuoksi on järkevintä käyttää silmukkamuuttujille sellaisia nimiä, joita ei käytetä muualla saman funktion
näkyvyysalueella
tai
globaalisti
.

Yksinäinen vektori multiavaruudessa

Yksikkövektorit ovat käteviä otuksia, oli ulottuvuuksia sitten kaksi tai seitsemäntoista. Niillä voidaan mm. esittää liikkuvan objektin suunta. Tällä kertaa työstettävänäsi on funktio, joka selvittää vektorista sitä vastaavan yksikkövektorin. Yksikkövektori on vektori, jonka pituus on 1. Yksikkövektorin komponentit saadaan kun jaetaan vektorin komponentit vektorin pituudella.
Opittavat asiat: Uuden
listan
kokoaminen toisen listan pohjalta
silmukassa
. Yksikkövektorin laskeminen.

Alustus:
Tehtävässä meillä on funktio, joka luo vektorista samansuuntaisen yksikkövektorin. Lataa koodipohja alempaa ja kirjoita siihen puuttuvat rivit kommenteille merkittyjen paikalle.
Koska funktiosi ei tiedä kuinka moniulotteisia vektoreita se joutuu pyörittelemään, ainoa mahdollisuus on kirjoittaa
for-silmukka
. Alkuperäinen vektori on
muuttujassa
v, joka on vektorin komponentit sisältävä
lista
. Vektorin pituus on muuttujassa pituus.
Tehtäväsi on kirjoittaa silmukka, joka käy läpi alkuperäisen vektorin, jakaa kunkin komponentin vektorin pituudella, ja lisää sen uuteen listaan, joka sijaitsee muuttujassa u. Anna
silmukkamuuttujan
nimeksi komponentti. Käytä lisäämiseen append-metodia. Huomaa, että voimme poikkeuksellisesti käyttää yksikirjaimisia muuttujia, koska ne ovat yleisiä nimiä vektoreille matematiikassa.

Haettu vastaus:
Kun olet saanut koodin toimivaksi, kopioi vastauslaatikkoon ne kaksi riviä, jotka kirjoitit kommenttien paikalle.

Resurssit:
vektori.py
def laske_pituus(v):
    nelio = 0
    for komponentti in v:
        nelio += komponentti ** 2
    return nelio ** 0.5

def yksikkovektoriksi(v): 
    u = []
    pituus = laske_pituus(v)
    # silmukan määrittely
    # silmukan sisältö (1 rivi)
    return u

print(yksikkovektoriksi([2.0, 2.0, 2.0, 2.0]))


Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Tässä vaiheessa pitäisi siis olla tiedossa miten
for-silmukka
määritellään, ja miten
silmukkamuuttujan
avulla voidaan
listassa
oleville
alkiolle
tehdä asioita. Kokeillaan siis laittaa tulosta-
funktioon
silmukka, jossa alkiot tulostetaan yksitellen.
def tulosta(kokoelma):
    for levy in kokoelma:
        print(levy)
Tuloste näyttää nyt tältä:
{'artisti': 'Alcest', 'albumi': 'Kodama', 'kpl_n': 6, 'kesto': '0:42:15', 'julkaisuvuosi': 2016}
{'artisti': 'Canaan', 'albumi': 'A Calling to Weakness', 'kpl_n': 17, 'kesto': '1:11:17', 'julkaisuvuosi': 2002}
{'artisti': 'Deftones', 'albumi': 'Gore', 'kpl_n': 11, 'kesto': '0:48:13', 'julkaisuvuosi': 2016}
{'artisti': 'Funeralium', 'albumi': 'Deceived Idealism', 'kpl_n': 6, 'kesto': '1:28:22', 'julkaisuvuosi': 2013}
{'artisti': 'IU', 'albumi': 'Modern Times', 'kpl_n': 13, 'kesto': '47:14', 'julkaisuvuosi': 2013}
{'artisti': 'Mono', 'albumi': 'You Are There', 'kpl_n': 6, 'kesto': '1:00:01', 'julkaisuvuosi': 2006}
{'artisti': 'Panopticon', 'albumi': 'Roads to the North', 'kpl_n': 8, 'kesto': '1:11:07', 'julkaisuvuosi': 2014}
{'artisti': 'PassCode', 'albumi': 'Clarity', 'kpl_n': 13, 'kesto': '49:27', 'julkaisuvuosi': 2019}
{'artisti': 'Scandal', 'albumi': 'Hello World', 'kpl_n': 13, 'kesto': '53:22', 'julkaisuvuosi': 2014}
{'artisti': 'Slipknot', 'albumi': 'Iowa', 'kpl_n': 14, 'kesto': '1:06:24', 'julkaisuvuosi': 2001}
{'artisti': 'Wolves in the Throne Room', 'albumi': 'Thrice Woven', 'kpl_n': 5, 'kesto': '42:19', 'julkaisuvuosi': 2017}
Selkeästi parempi kuin aiemmin, mutta ei vielä näytä ihan samalta kuin aikaisemmissa kauniissa ajatuksissa.

Listat julki

Listojen
ja muiden
tietorakenteiden
tulostaminen on aina oma ongelmansa, ja sen ratkaisu riippuu pitkälti siitä mitä ohjelmalla halutaan tehdä. Yksi vaihtoehtoja voimakkaasti rajoittava tekijä on listan pituus. Jos listan pituus vaihtelee, se rajoittaa huomattavasti sitä, miten se voidaan tulostaa. Meidän ohjelmamme tapauksessa itse kokoelman pituus voi vaihdella, minkä vuoksi tulostammekin sen
silmukalla
. Listan sisältämien sanakirjojen käytettäköön tässä vaiheessa yksinkertaista printtiä.
def tulosta(kokoelma):
    for levy in kokoelma:
        print(
            f"{levy['artisti']}, {levy['albumi']}, {levy['kpl_n']}, "
            f"{levy['kesto']}, {levy['julkaisuvuosi']}"
        )
Tämä tuottaa melkein toivotun näköisen tulosteen, joskin eteen laitetut järjestysnumerot puuttuvat. Miten ne lisätään? Yksi looginen vaihtoehto olisi tehdä laskuri:
def tulosta(kokoelma):
    numero = 1
    for levy in kokoelma:
        print(
            f"{numero:2}. "
            f'{levy["artisti"]}, {levy["albumi"]}, {levy["kpl_n"]}, '
            f'{levy["kesto"]}, {levy["julkaisuvuosi"]}'
        )
        numero += 1
Eli otetaan kokonaislukumuuttuja, jolla on alkuarvona 1, ja lisätään siihen 1 jokaisella kierroksella. On kuitenkin olemassa nätimpi tapa saada
indeksit
käyttöön for-silmukan sisällä. Käytännössähän tuo järjestysnumero on sama kuin alkion indeksi listassa + 1. Kirjoitetaan koodirivi ensin ja ihmetellään sitä jälkeenpäin:
def tulosta(kokoelma):
    for i, levy in enumerate(kokoelma):
        print(
            f"{i + 1:2}. "
            f"{levy['artisti']}, {levy['albumi']}, {levy['kpl_n']}, "
            f"{levy['kesto']}, {levy['julkaisuvuosi']}"
        )
Ensimmäinen kysymys on: mikä on tuo mystinen enumerate? Tyypilliseen tapaan asiaa voidaan tutkia
tulkissa
. Koska levylistassa on vähän liikaa tavaraa alkiota kohti, otetaan käyttöön aiemmin esitelty eläinlista.
In [1]: elukoita = ["koira", "kissa", "orava", "mursu", "aasi", "laama"]
In [2]: enumerate(elukoita)
Out[2]: <enumerate at 0x7fb34458a5e8>
Tämähän oli hyödyllistä informaatiota. Sattumoisin enumerate tuottaa
generaattorimaisen
objektin, joita voidaan kyllä käydä läpi silmukalla, mutta eivät ole
tietorakenteita
vaan funktioita, jotka tuottavat tietyn sekvenssin seuraavan arvon kun niitä kutsutaan. Generaattorin - ja enumeraten - voi kuitenkin purkaa listaksi, joten otetaan otto 2:
In [3]: list(enumerate(elukoita))
Out[3]:
[(0, 'koira'),
 (1, 'kissa'),
 (2, 'orava'),
 (3, 'mursu'),
 (4, 'aasi'),
 (5, 'laama')]
Listan sisällä esiintyvät sulkeissa olevat tietorakenteet ovat nimeltään
monikkoja
. Niistä ei ole vielä puhuttu, mutta eipä niissä ole paljon kerrottavaakaan: monikko on listan
muuntumaton
sukulainen. Monikkoa siis luetaan kuin listaa, mutta sitä ei voi muokata. Jos monikkoja sisältävää listaa käydään läpi yhden
muuttujan
silmukalla, kullakin kierroksella muuttuja saa arvoksi monikon. Silmukkamuuttujien kanssa voidaan kuitenkin tehdä sama temppu kuin tapauksessa, jossa
funktiokutsu
palauttaa useita muuttujia. Eli kun tiedetään varmuudella, että listan jokaisessa
alkiossa
on sisällä kaksi alkiota, se voidaan suoraan purkaa kahteen muuttujaan kuten kokoelmaesimerkissä jo tehtiin. Sama elukoilla:
In [4]: for i, elain in enumerate(elukoita):
   ...:     print(f"{i}. {elain}")
   ...:
0. koira
1. kissa
2. orava
3. mursu
4. aasi
5. laama
Tästä nähdään, että sekä i että elain saavat jokaisella silmukan
kierroksella
uudet arvot. Valittu
silmukkamuuttujan
nimi i on hyvin tyypillinen tämäntapaisissa silmukoissa kaikissa ohjelmointikielissä. Jos silmukoita on sisäkkäin useampia, valitaan seuraavaksi puolestaan j, sitten k. Pidempien nimien käyttökin on toki sallittua.
Alla on kaksi muuta tapaa kirjoittaa vastaava toiminallisuus, joka selventää millaisten kokonaisuuksien kanssa edellisen esimerkin toiminta on identtistä. Ensin tekemällä alkion purkaminen eri rivillä, mistä seuraa yksi ylimääräinen rivi:
In [5]: for alkio in enumerate(elukoita):
   ...:     i, elain = alkio
   ...:     print(f"{i}. {elain}")
Toiseksi käyttämällä
indeksiosoitusta
suoraan tulostusrivillä, joka taas tekee tulostusrivistä vähemmän selkeän:
In [6]: for alkio in enumerate(elukoita):
   ...:     print(f"{alkio[0]}. {alkio[1]}")

Inventaarioinsinööri

Yksinkertaisessa inventaario-ohjelmassa käsitellään listaa, joka sisältää esineiden nimiä sekä kappalemääriä. Vastaavissa tapauksissa on usein hyödyksi antaa kullekin arvolle oma nimensä jo silmukan määrittelyvaiheessa. Tästä syystä Python tukee useiden silmukkamuuttujien määrittelyä yhdessä lauseessa.
Opittavat asiat: Kahta
silmukkamuuttujaa
käyttävän
for-silmukan
määrittely.

Alustus:
Koska kyseessä on jälleen hieman monimutkaisempi kokonaisuus, olemme kasanneet resurssiksi koodipohjan. Korvaa
kommentilla
merkitty rivi halutunlaisella
silmukan
määrittelyllä. Kuten koodipohjasta voidaan nähdä, läpikäytävä
lista
sisältää kahden
alkion
monikkoja
. Molemmat alkiot pitää nyt ottaa omaan muuttujaansa, joille annettakoon nimet nimi ja kpl.
Tiedät määritelleesi silmukan oikein, kun saat seuraavat tulostukset:
Varastossa on 12 x aasi
Varastossa on 1 x muumimuki
Varastossa on 4 x varsikirves

Haettu vastaus:
Kun olet saanut koodin toimimaan, kopioi kirjoittamasi silmukkamäärittely vastauslaatikkoon. Rivejä tulisi olla siis tasan yksi.

Resurssit:
inventaario.py
inventaario = [("aasi", 12), ("muumimuki", 1), ("varsikirves", 4)]

# silmukan määrittely tähän
    print(f"Varastossa on {kpl} x {nimi}")

Kirjoita silmukkamäärittelyrivi vastauslaatikkoon
Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Listojen tulostukseen liittyy vielä yksi konsti, joka on erityisen kätevä tulostettaessa listojan joiden pituutta ei tiedetä ennalta, mutta kuitenkin halutaan tulostaa sen sisältö yhdelle riville. Esimerkkinä otettakoon vaikka ohjelma, johon käyttäjä
syöttää
sanoja. Sanat laitetaan listaan, ja yksi ohjelman toiminnoista on tulostaa syötetyt sanat. Koska syötettyjen sanojen lista voi olla miten pitkä tahansa, ei voida käyttää merkkijonon muotoilua, koska
paikanpitimien
määrää ei voida tietää. Sen sijaan voidaan käyttää join-nimistä merkkijono
metodia
. Tämän käyttö on hieman erikoisen näköistä.

Pilkkuja, pilkkuja kaikkialla

Opittavat asiat: Miltä join-
metodia
käyttävä tulostus näyttää.

Alustus:
Suorita seuraavat rivit
tulkissa
:
In [1]: elukoita = ["koira", "kissa", "orava", "mursu", "aasi", "laama"]
In [2]: print(",".join(elukoita))

Haettu vastaus:
Kopioi vastauslaatikkoon tulkin antama tulostus.
Kopioi saamasi tuloste alle.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Tarkalleen ottaen join-metodi toimii siten, että se liittää
listan
alkiot
yhteen merkkijonoksi käyttäen "liittimenä"
merkkijonoa
. Tässä mielessä se on kuin käänteinen split. Kuten split, myös join on merkkijonon metodi, mistä johtuu myös hieman outo
syntaksi
, jossa liittämiseen käytettävä merkkijono on rivillä ensin, ja liitettävä lista vasta
metodikutsun
argumenttina. Syynä on todennäköisesti se, että join pystyy toimimaan minkä tahansa
sekvenssityyppisen
objektin kanssa, mutta liittimen on aina oltava merkkijono - niinpä metodi on kiinnitetty siihen sen sijaan, että se toteutettaisiin erikseen jokaiselle sekvenssityypille.
Kyseisen metodin käyttö listojen tulostamiseen on sen verran näppärä temppu, että sitä voi hyvin käyttää silloinkin kun listan pituus tiedetään. Sen lisäksi, että joinia käyttävä rivi on huomattavasti kompaktimpi, sen toiminta on myös dynaamisempi. Tästä johtuen muutokset muualla koodissa harvemmin johtavat yllättäviin virheisiin joinia käyttävässä tulostuksessa. Esimerkkiohjelmamme käyttää
sanakirjoja
, mutta teoriassa joinia voisi käyttää, jos haetaan sanakirjasta pelkät arvot listana values-metodilla:
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/joku/kansio/kokoelma.py in <module>()
     77         poista(kokoelma)
     78     elif valinta == "t":
---> 79         tulosta(kokoelma)
     80     elif valinta == "q":
     81         break

/joku/kansio/kokoelma.py in tulosta(kokoelma)
     62 def tulosta(kokoelma):
     63     for i, levy in enumerate(kokoelma):
---> 64         print(f"{:2}. {', '.join(levy.values())})
     65
     66 kokoelma = lataa_kokoelma()

TypeError: sequence item 0: expected str instance, int found
Tästä ilmenee tärkeä rajoitus:
listan
(tai vastaavan) kaikkien
alkioiden
tulee olla
merkkijonoja
, jotta join-metodia voidaan käyttää. Ratkaisuvaihtoehdot tässä tilanteessa ovat: a) käyttää jotain muuta menetelmää tai b) muuttaa kaikki listan alkiota merkkijonoiksi ennen join-metodin käyttöä. Mahdollista on myös sisällyttää alunperinkin kaikki numerot sanakirjoihin merkkijonoina, mutta silloin niillä ei voi enää suorittaa laskutoimituksia. Jälleen kerran riippuu hyvin paljon ohjelman tarkoituksesta, mitä menetelmää kannattaa käyttää.

Väleillä on väliä

Edellisen tehtävän join-esimerkissä on yksi huutava puute: välilyönnit puuttuvat pilkkujen jäljestä. Asia on toki helppo korjata, sillä join ei aseta mitään rajoituksia sille, miten pitkällä merkkijonolla se liittää listan alkiot yhteen.
Opittavat asiat: Join-
metodin
käyttö.

Alustus:
Alkutilanne on sama kuin edellisessä tehtävässä, eli olemme määritelleet listan elukoista:
In [1]: elukoita = ["koira", "kissa", "orava", "mursu", "aasi", "laama"]

Haettu vastaus:
Vastaukseen halutaan koodirivi, joka tulostaa tämän
listan
sisällön siten, että
alkioiden
välissä on pilkku ja välilyönti, kuten on hyvien tapojen mukaista. Kun olet saanut
tulkissa
oikean näköisen tulostuksen, kopioi sen aikaansaanut rivi vastauslaatikkoon.
Kopioi rivi alle.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Esimerkkikoodissa käytettäköön siis tätä ratkaisua:
def tulosta(kokoelma):
    for i, levy in enumerate(kokoelma):
        print(
            f"{i + 1:2}. "
            f"{levy['artisti']}, {levy['albumi']}, {levy['kpl_n']}, "
            f"{levy['kesto']}, {levy['julkaisuvuosi']}"
        )

Uusi maailmanjärjestys

Toistaiseksi olemme saaneet aikaan tämän näköisen koodin levykatalogiohjelmallemme. Jos olet seurannut koodin kehitystä päivittämällä itsellesi materiaalin aikana tehtyjä muutoksia, pitäisi koneellasi olla samanlainen koodi. Ainoastaan funktioiden määrittelyjärjestys voi hieman erota.
def kysy_luku(kysymys):
    while True:
        try:
            luku = int(input(kysymys))
        except ValueError:
            print("Arvon tulee olla kokonaisluku")
        else:
            return luku

def kysy_aika(kysymys):
    return input(kysymys)

def lataa_kokoelma():
    """
    Luo testikokoelman. Palauttaa listan, joka sisältää viiden avain-arvo-parin
    sanakirjoja.
    Sanakirjan avaimet vastaavat seuraavia tietoja:
    "artisti" - artisti nimi
    "albumi" - levyn nimi
    "kpl_n" - kappaleiden määrä
    "kesto" - kesto
    "julkaisuvuosi" - julkaisuvuosi
    """

    kokoelma = [
        {
            "artisti": "Alcest",
            "albumi": "Kodama",
            "kpl_n": 6,
            "kesto": "42:15",
            "julkaisuvuosi": 2016
        },
        {
            "artisti": "Canaan",
            "albumi": "A Calling to Weakness",
            "kpl_n": 17,
            "kesto": "1:11:17",
            "julkaisuvuosi": 2002
        },
        {
            "artisti": "Deftones",
            "albumi": "Gore",
            "kpl_n": 11,
            "kesto": "48:13",
            "julkaisuvuosi": 2016
        },
        # katkaistaan tästä, koko esimerkin koodissa määritelty 8 lisää
    ]
    return kokoelma

def tallenna_kokoelma(kokoelma):
    """
    Tallentaa kokoelman, joskus tulevaisuudessa.
    """

    pass

def lisaa(kokoelma):
    print("Täytä lisättävän levyn tiedot. Jätä levyn nimi tyhjäksi lopettaaksesi")
    while True:
        levy = input("Levyn nimi: ")
        if not levy:
            break

        artisti = input("Artistin nimi: ")
        kpl_n = kysy_luku("Kappaleiden lukumäärä: ")
        kesto = kysy_aika("Kesto: ")
        vuosi = kysy_luku("Julkaisuvuosi: ")
        kokoelma.append({
            "artisti": artisti,
            "albumi": levy,
            "kpl_n": kpl_n,
            "kesto": kesto,
            "julkaisuvuosi": vuosi
        })
        print("Levy lisätty")

def poista(kokoelma):
    """
    Poistaa leven kokoelmasta, joskus tulevaisuudessa.
    """

    pass

def tulosta(kokoelma):
    for i, levy in enumerate(kokoelma):
        print(
            f"{i + 1:2}. "
            f"{levy['artisti']}, {levy['albumi']}, {levy['kpl_n']}, "
            f"{levy['kesto']}, {levy['julkaisuvuosi']}"
        )

kokoelma = lataa_kokoelma()
print("Tämä ohjelma ylläpitää levykokoelmaa. Voit valita seuraavista toiminnoista:")
print("(L)isää uusia levyjä")
print("(P)oista levyjä")
print("(T)ulosta kokoelma")
print("(Q)uittaa")
while True:
    valinta = input("Tee valintasi: ").strip().lower()
    if valinta == "l":
        lisaa(kokoelma)
    elif valinta == "p":
        poista(kokoelma)
    elif valinta == "t":
        tulosta(kokoelma)
    elif valinta == "q":
        break
    else:
        print("Valitsemaasi toimintoa ei ole olemassa")
tallenna_kokoelma(kokoelma)
Koodin määrän puolesta tämä on noin kolmasosa~puolet lopputyöstä. Seuraavaksi lähdemme toteuttamaan lisäominaisuutta, joka johdattaa meidät uusiin listoilla tehtäviin asioihin: sisällön järjestämiseen ja sisällön leikkaamiseen. Lisätään siis ohjelmaan uusi funktio:
def jarjesta(kokoelma):
    pass
Ja lisätään päävalikkoon vastaava toiminto muokkaamalla pääohjelmaa:
kokoelma = lataa_kokoelma()
print("Tämä ohjelma ylläpitää levykokoelmaa. Voit valita seuraavista toiminnoista:")
print("(L)isää uusia levyjä")
print("(P)oista levyjä")
print("(J)ärjestä kokoelma")
print("(T)ulosta kokoelma")
print("(Q)uittaa")
while True:
    valinta = input("Tee valintasi: ").strip().lower()
    if valinta == "l":
        lisaa(kokoelma)
    elif valinta == "p":
        poista(kokoelma)
    elif valinta == "j":
        jarjesta(kokoelma)
    elif valinta == "t":
        tulosta(kokoelma)
    elif valinta == "q":
        break
    else:
        print("Valitsemaasi toimintoa ei ole olemassa")
tallenna_kokoelma(kokoelma)
Osaamistavoitteet: Tutkimme miten listoja voidaan järjestää sort-metodilla ja sopivilla apufunktioilla. Lisäksi merkkijonojen järjestettävyydestä opitaan uusia asioita.

Järjestystä, kiitos!

Kuvalähde 8
Kokoelma pitäisi saada siis järjestettyä. Tavoitteena on, että käyttäjä voi valita, minkä kentän perusteella kokoelma järjestetään ja onko järjestys nouseva vai laskeva (siis pienimmästä suurimpaan vai toisin päin). Kaikki tämä hoituu käyttämällä
listojen
sort-
metodia
:
In [1]: lista_1 = [37, 5, 12]
In [2]: lista_1.sort()
In [3]: lista_1
Out[3]: [5, 12, 37]
Tämä metodi järjestää listan
alkiot
nousevaan suuruusjärjestykseen, ts. pienin alkio ensin ja suurin viimeisenä. Luvuille tämä on helppo ymmärtää. Merkkijonoille järjestäminen perustuu aakkosjärjestykseen:
In [1]: elukoita = ["mursu", "apina", "aasi", "laama", "koala", "aropupu", "hirvi"]
In [2]: elukoita.sort()
In [3]: elukoita
Out[3]: ['aasi', 'apina', 'aropupu', 'hirvi', 'koala', 'laama', 'mursu']
Listojen
keskinäinen järjestys perustuu puolestaan oletuksena ensimmäisten alkioiden vertailulle. Näiden ollessa samat, vertaillaan toista alkiota jne. Kokoelmamme sisältää kuitenkin sanakirjoja, joten järjestäminen ilman mitään lisämäärteitä aiheuttaa TypeError-
poikkeuksen
. Tätä varten sort-
metodissa
on
valinnainen argumentti
key. Tällä argumentilla voidaan määritellä
funktio
, jolla kaikki
alkiot
käsitellään ennen vertailua. Tarkastellaan ensin yksinkertaista tilannetta, jossa käytetään Pythonissa valmiiksi olevaa funktiota. Numeroita sisältävien
merkkijonojen
järjestäminen aiheuttaa joskus kummallisia tuloksia:
In [1]: luvut = ["2", "12", "5", "43", "48"]
In [2]: luvut.sort()
In [3]: luvut
Out[3]: ['12', '2', '43', '48', '5']
Jos tavoitteena oli saada lukuja esittävät merkkijonot niiden numeeriseen suuruusjärjestykseen, tulos ei ole toivottu. Asian voi korjata käyttämällä int-funktiota key-argumenttina:
In [4]: luvut.sort(key=int)
In [5]: luvut
Out[5]: ['2', '5', '12', '43', '48']
Tämä on ensimmäinen tilanne tässä materiaalissa, kun
funktion
nimeä käytetään oikeassa koodissa ilman, että perässä olisi
kutsumista
merkitsevät sulut. Tämä on erityinen mekanismi ohjelmoinnissa, jota kutsutaan
kutsupyynnöksi
. Tässä mekanismissa funktion suoran kutsumisen sijaan kerrotaan jollekin toiselle ohjelman osalle, mitä funktiota sen tulee kutsua. Jotta kutsupyyntö voi toimia, funktion tulee vastata argumenttien lukumäärältä ja tyypeiltä sitä, mitä funktiota käyttävä ohjelman osa vaatii.
Tässä tapauksessa kutsuttava ohjelman osa on sort-metodi, jonka key-argumentilla voidaan määrittää kutsupyyntö. Metodi kutsuu tähän parametriin annettua funktiota siinä vaiheessa, kun se tarvitsee
vertailuarvon
kustakin listan alkiosta. Tässä tapauksessa funktion tulee olla sellainen, joka saa yhden argumentin ja
palauttaa
yhden arvon. Meidän tarkoitukseemme ei tosin sovi mikään valmis funktio. Tarvitsemme nimittäin funktion, joka valitsee yhden kentän edustamaan koko sanakirjaa.
Koska key-argumenttina olevaa funktiota kutsutaan tasan yhdellä argumentilla, funktiolle ei voi välittää tietoa siitä, mikä kenttä tulisi valita. Ainoa tuntemamme tapa sisällyttää tämä tieto on siis tehdä jokaista kenttää varten oma funktionsa. Ei kovin optimaalista, mutta valitettavasti pakollista tämän materiaalin antamien tietojen puitteissa. Parempiin keinoihin voi perehtyä Pythonin dokumentaatiota lukemalla. Nämä apufunktiot, joita tulemme omassa koodissamme antamaan key-argumenteiksi, ovat varsin yksinkertaisia:
def valitse_artisti(levy):
    return levy["artisti"]
Funktio palauttaa siis kustakin levystä sen "artisti"-avainta vastaavan kentän käytettäväksi sort-metodin vertailussa. Vastaavasti muut neljä:
def valitse_albumi(levy):
    return levy["albumi"]

def valitse_kpl_n(levy):
    return levy["kpl_n"]

def valitse_kesto(levy):
    return levy["kesto"]

def valitse_julkaisuvuosi(levy):
    return levy["julkaisuvuosi"]

Varastovalitsin

Palaamme jälleen kerran inventaarion hallinnan ääreen. Tällä kertaa työn alla on funktio, josta on apua kun inventaario halutaan järjestää varastossa olevan lukumäärän mukaan.
Opittavat asiat: Sort-
metodille
key-
argumentiksi
kelpaavan
funktion
määrittely ja toteutus.

Toteutettava funktio: valitse_lukumaara
  • Parametrit
    :
    • monikko
      joka sisältää tavaran tuotekoodin sekä varastossa olevien kappaleiden lukumäärän
  • Palauttaa
    :
    • Varastossa olevien kappaleiden lukumäärän (kokonaisluku)
Funktion tulee siis palauttaa
indeksiosoitusta
käyttämällä saamastaan monikosta sen toinen
alkio
.
Vaikka funktio on suunniteltu juuri tiettyä käyttötarkoitusta varten (
vertailuarvoksi
), siinä ei itsessään ole mitään erikoista. Ainoat rajoitteet ovat, että sillä tulee olla tasan yksi parametri ja sen tulee palauttaa tasan yksi arvo.

Funktion testaus:
Voit testata funktiotasi vaikkapa oheisella monikolla:
tavara = ("a45i", 12)
Kun tämä annetaan tehdyn funktion argumentiksi, pitäisi lopputuloksen olla 12.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Itse jarjesta-funktio noudattaa pitkälti tuttua kaavaa, eli siinä kysytään, minkä kentän mukaan halutaan järjestää, ja sitten
ehtorakenteessa
valitaan oikea järjestystapa:
def jarjesta(kokoelma):
    print("Valitse kenttä jonka mukaan kokoelma järjestetään syöttämällä kenttää vastaava numero")
    print("1 - artisti")
    print("2 - levyn nimi")
    print("3 - kappaleiden määrä")
    print("4 - levyn kesto")
    print("5 - julkaisuvuosi")
    kentta = input("Valitse kenttä (1-5): ")
    if kentta == "1":
        kokoelma.sort(key=valitse_artisti)
    elif kentta == "2":
        kokoelma.sort(key=valitse_albumi)
    elif kentta == "3":
        kokoelma.sort(key=valitse_kpl_n)
    elif kentta == "4":
        kokoelma.sort(key=valitse_kesto)
    elif kentta == "5":
        kokoelma.sort(key=valitse_julkaisuvuosi)
    else:
        print("Kenttää ei ole olemassa")
Koska olemme kaukaa viisaasti päättäneet käyttää nimenomaan numeroita kappaleiden määrän tallentamiseen, niidenkin osalta järjestäminen tapahtuu oikein. Kesto sen sijaan tuottaa hieman ongelmallisen näköisiä tuloksia:
 1. Mono, You Are There, 6, 1:00:01, 2006
 2. Slipknot, Iowa, 14, 1:06:24, 2001
 3. Panopticon, Roads to the North, 8, 1:11:07, 2014
 4. Canaan, A Calling to Weakness, 17, 1:11:17, 2002
 5. Funeralium, Deceived Idealism, 6, 1:28:22, 2013
 6. Alcest, Kodama, 6, 42:15, 2016
 7. Wolves in the Throne Room, Thrice Woven, 5, 42:19, 2017
 8. IU, Modern Times, 13, 47:14, 2013
 9. Deftones, Gore, 11, 48:13, 2016
10. PassCode, Clarity, 13, 49:27, 2019
11. Scandal, Hello World, 13, 53:22, 2014
Järjestys on muutoin pienimmästä suurimpaan, mutta kaikki yli tunnin levyt ovat sort-
metodin
mielestä lyhyempiä kuin alle tunnin levyt. Tämä johtuu tietenkin tutusta ongelmasta: yli tunnin kestävät levyt alkavat merkillä "1", joka on pienempi kuin muut numerot – paitsi nolla. Järjestämisen kannalta olisikin parempi, jos kaikissa kestoissa olisi merkittynä tunnit silloinkin, kun levy kestää alle tunnin. Samaisesta syystä ohjelmoijat rakastavat päivämääriä, jotka ovat muodossa vuosi-kuukausi-päivä - ne nimittäin järjestyvät oikeaan aikajärjestykseen suoraan sortilla, mikäli vain kaikissa numeroissa on etunollat (esim. 2015-07-22).
Ensimmäinen askel on tietenkin lisätä nuo nollatunnit lataa_kokoelma-funktion tuottamaan mallikokoelmaan.
def lataa_kokoelma():
    """
    Luo testikokoelman. Palauttaa listan, joka sisältää viiden avain-arvo-parin
    sanakirjoja.
    Sanakirjan avaimet vastaavat seuraavia tietoja:
    "artisti" - artisti nimi
    "albumi" - levyn nimi
    "kpl_n" - kappaleiden määrä
    "kesto" - kesto
    "julkaisuvuosi" - julkaisuvuosi
    """

    kokoelma = [
        {
            "artisti": "Alcest",
            "albumi": "Kodama",
            "kpl_n": 6,
            "kesto": "0:42:15",
            "julkaisuvuosi": 2016
        },
        {
            "artisti": "Canaan",
            "albumi": "A Calling to Weakness",
            "kpl_n": 17,
            "kesto": "1:11:17",
            "julkaisuvuosi": 2002
        },
        {
            "artisti": "Deftones",
            "albumi": "Gore",
            "kpl_n": 11,
            "kesto": "0:48:13",
            "julkaisuvuosi": 2016
        },
        # katkaistaan tästä, koko esimerkin koodissa määritelty 8 lisää
    ]
    return kokoelma
Tämä ei kuitenkaan vielä takaa mitään, sillä käyttäjä voi levyjä
syöttäessään
jättää tunnit pois. Tällaisten korjaaminen pitäisi ylipäänsäkin olla koodin eikä käyttäjän tehtävä. Meillä on sopivasti olemassa jo
funktio
, jota käytetään kestojen syöttämiseen. Toistaiseksi siellä ei tosin ole ollut erityisesti sisältöä. Lisätään nyt funktioon kaksi asiaa:
  1. Tarkistus, että käyttäjän syöte on oikeanlainen.
  2. Nollatuntien lisäys tarvittaessa.
Tämä onnistuu, kun käyttäjän syöte splitataan kaksoispisteen kohdalta ja tutkitaan saatuja osia erikseen. Oletetaan, että kaikki levyt ovat alle 10 tuntia, joten yksi nolla tunteihin riittää, eikä etunollia siten tarvita yli tunnin levyihin.
def kysy_aika(kysymys):
    while True:
        osat = input(kysymys).split(":")
        if len(osat) == 3:
            h, min, s = osat
        elif len(osat) == 2:
            min, s = osat
            h = "0"
        else:
            print("Anna aika muodossa tunnit:minuutit:sekunnit tai minuutit:sekunnit")
            continue

        try:
            h = int(h)
            min = int(min)
            s = int(s)
        except ValueError:
            print("Aikojen on oltava kokonaislukuja")
            continue

        if not (0 <= min <= 59):
            print("Minuuttien on oltava välillä 0-59")
            continue
        if not(0 <= s <= 59):
            print("Sekuntien on oltava välillä 0-59")
            continue
        if h < 0:
            print("Tuntien on oltava positiivinen kokonaisluku")
            continue

        return f"{h}:{min:02}:{s:02}"
Yhtäkkiä fuktio onkin aika pitkä. Pituutta lisäävät erityisesti yksittäisten osien tarkistukset: täytyy varmistaa että ne ovat lukuja ja lisäksi tarkistaa, että ne ovat oikeita kellonaikoja.
Funktiossa esiintyy myös uusi
avainsana
continue. Siinä missä
break
lopettaa
silmukan
suorituksen, continue lopettaa meneillään olevan
kierroksen
ja hyppää uuden kierroksen alkuun. Eli heti, jos törmätään johonkin tarkistukseen, jota käyttäjän syöte ei läpäise, palataan kysymään uutta. Tässä continueta on käytetty, koska muuten kaikkien tarkistusten tulisi olla toistensa sisällä, mistä seuraisi hyvin hankalan näköinen
ohjausrakenne
. Lisäselvennystä continuen toiminnasta antaa animaatio:
Huomaa myös, että return on tällä kertaa
while-silmukan
lopussa. Kun nimittäin löydetään sellainen
syöte
, joka läpäisee kaikki testit, se voidaan
palauttaa
ja samalla lopettaa silmukan läpikäyminen (koska funktio, joka sisältää sen, päättyy returniin).
Yleisesti ottaen
continue
on suhteellisen harvoin käytettävä lause
silmukoissa
. Sitä tarvitsee oikeastaan vain juuri tämän kaltaisissa tilanteissa, missä tehdään useita tarkistuksia, joista mikä tahansa voi aiheuttaa seuraavaan kierrokseen jatkamisen, oli kyse sitten syötteen kysymisestä uudestaan
while-silmukassa
tai
for-silmukan
tapauksessa siirtymisestä seuraavan
alkion
käsittelyyn. Huomattavaa on, että continuen käytön voi aina korvata sisäkkäisillä
ehtorakenteilla
. Kyseessä on siis vain kätevä työkalu, jolla tietynlaisiin silmukoihin saadaan hieman selkeämpää koodia.
Kaikkien näiden muutosten jälkeen kokoelmaan voidaan nyt lisätä levyjä, joiden kesto on alle tunnin, ja keston mukaan järjestäminen toimii edelleen.
Tämä ohjelma ylläpitää levykokoelmaa. Voit valita seuraavista toiminnoista:
(L)isää uusia levyjä
(M)uokkaa levyjä
(P)oista levyjä
(J)ärjestä kokoelma
(T)ulosta kokoelma
(Q)uittaa
Tee valintasi: l
Täytä lisättävän levyn tiedot. Jätä levyn nimi tyhjäksi lopettaaksesi
Levyn nimi: Rotten Tongues
Artistin nimi: Curse Upon a Prayer
Kappaleiden lukumäärä: 9
Kesto: 43:17
Julkaisuvuosi: 2015
Levyn nimi:
Tee valintasi: j
Valitse kenttä jonka mukaan kokoelma järjestetään syöttämällä kenttää vastaava numero
1 - artisti
2 - levyn nimi
3 - kappaleiden määrä
4 - levyn kesto
5 - julkaisuvuosi
Valitse kenttä (1-5): 4
Tee valintasi: t
 1. Alcest, Kodama, 6, 0:42:15, 2016
 2. Wolves in the Throne Room, Thrice Woven, 5, 0:42:19, 2017
 3. Curse Upon a Prayer, Rotten Tongues, 9, 0:43:17, 2015
 4. IU, Modern Times, 13, 0:47:14, 2013
 5. Deftones, Gore, 11, 0:48:13, 2016
 6. PassCode, Clarity, 13, 0:49:27, 2019
 7. Scandal, Hello World, 13, 0:53:22, 2014
 8. Mono, You Are There, 6, 1:00:01, 2006
 9. Slipknot, Iowa, 14, 1:06:24, 2001
10. Panopticon, Roads to the North, 8, 1:11:07, 2014
11. Canaan, A Calling to Weakness, 17, 1:11:17, 2002
12. Funeralium, Deceived Idealism, 6, 1:28:22, 2013
Esimerkistä myös nähdään, että ohjelma lisää nollatunnit oikein.
Lopulta toteutamme vielä mahdollisuuden vaihtaa järjestys nousevasta laskevaksi. Tämä onnistuu sort-
metodin
toisella
valinnaisella argumentilla
. Metodilla on nimittäin valinnainen argumentti reverse, joka saa
oletuksena
arvon False. Halutessamme voimme asettaa sen Trueksi, jolloin järjestäminen tehdään käänteisesti. Tarvitsee siis vain lisätä jarjesta-funktioon kysymys, haluaako käyttäjä järjestyksen nousevana vai laskevana.
def jarjesta(kokoelma):
    print("Valitse kenttä jonka mukaan kokoelma järjestetään syöttämällä kenttää vastaava numero")
    print("1 - artisti")
    print("2 - levyn nimi")
    print("3 - kappaleiden määrä")
    print("4 - levyn kesto")
    print("5 - julkaisuvuosi")
    kentta = input("Valitse kenttä (1-5): ")
    jarjestys = input("Järjestys; (l)askeva vai (n)ouseva: ").lower()
    if jarjestys == "l":
        kaanna = True
    else:
        kaanna = False
    if kentta == "1":
        kokoelma.sort(key=valitse_artisti, reverse=kaanna)
    elif kentta == "2":
        kokoelma.sort(key=valitse_levy, reverse=kaanna)
    elif kentta == "3":
        kokoelma.sort(key=valitse_n, reverse=kaanna)
    elif kentta == "4":
        kokoelma.sort(key=valitse_kesto, reverse=kaanna)
    elif kentta == "5":
        kokoelma.sort(key=valitse_vuosi, reverse=kaanna)
    else:
        print("Kenttää ei ole olemassa")
Kysytään siis toinen
syöte
, ja sen perusteella asetetaan reverse-argumentiksi annettavan
muuttujan
arvo Trueksi tai Falseksi. Tällä kertaa mikä tahansa syöte joka ei ole l tai L asettaa järjestyksen nousevaksi, koska se on oletus.

Varaston järjestelyä

Kuten todettua, listoja järjestävän sort-metodin kanssa voidaan järjestykseen vaikuttaa valinnaisilla argumenteilla. Tämä tehtävä on jatkoa edelliselle: käytämme siinä määriteltyä funktiota apuna inventaariolistan järjestämisessä.
Opittavat asiat: Itsemääritetyn
funktion
käyttö
listan
järjestämisessä sort-
metodilla
.
Alustus:
Käytä edellisen tehtävän kooditiedostoa pohjana. Laita
pääohjelmaksi
:
inventaario = [("aasi", 12), ("muumimuki", 1), ("varsikirves", 4)]
# kirjoita tähän rivi joka järjestää inventaarion kappalelukumäärien mukaan laskevassa järjestyksessä
print(inventaario)
Haettu vastaus:
Vastaukseksi halutaan koodirivi, jonka kirjoitit kommentin tilalle em. pääohjelmakoodiin. Ohjelman suorituksen tulisi antaa tulos laskevassa järjestyksessä eli tavara jota on eniten varastossa ensimmäiseksi ja se jota vähiten viimeiseksi. Lopputulos pitäisi olla siis:
[('aasi', 12), ('varsikirves', 4), ('muumimuki', 1)]
Syötä listan kuvaillulla tavalla järjestävä koodirivi vastauslaatikkoon.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Tulostusten kauneusleikkaus

Esitellään tässä viimeisessä osiossa vielä, miten listojen leikkaamisia voi hyödyntää tulosteen karsimisessa. Varsinkin jos kokoelma kasvaa suurempiin mittoihin, tulosteen selailu voi olla rasittavaa. Kehitellään alkeellinen karsimisratkaisu, joka näyttää 20 tulosta kerrallaan ja seuraavat 20 sitten, kun käyttäjä painaa enteriä, jne. Kaunistellaan tulostetta myös hieman.
Osaamistavoitteet: Tämän osion jälkeen pitäisi olla käsitys siitä, miten listojen leikkauksia käytetään. Lisäksi tutustumme for-silmukan erikoistapaukseen, jota käytetään toistamaan silmukassa oleva koodi tietty määrä kertoja.

Lista tulostuu pätkittäin

Tarkoitus on siis tulostaa kokoelma-listasta aina 20 levyä kerrallaan ja sitten jäädä odottamaan, että käyttäjä painaa enteriä. Lähdetään liikkeelle helpoimmasta vaatimuksesta, eli miten otetaan
listasta
ulos 20 ensimmäistä
alkioita
. Esimerkin lyhyyden nimissä tosin käytämme pienempiä numeroarvoja ja listojen pituuksia. Otetaan siis tutuksi tulleesta elukkalistasta ensimmäiset kolme eläintä:
In [1]: elukoita = ["mursu", "apina", "aasi", "laama", "koala", "aropupu", "hirvi"]
In [2]: top3 = elukoita[:3]
In [3]: top3
Out[3]: ['mursu', 'apina', 'aasi']
Varsinainen uusi asia on toisella rivillä. Merkintä [:3] tarkoittaa
leikkausta
, joka alkaa listan alusta ja päättyy ennen
indeksiä
3. Kaksoispisteen vasemmalla puolella on ensimmäisen leikkaukseen mukaan tulevan alkion indeksi. Sen puuttuessa oletetaan paikalle 0. Kaksoispisteen oikealla puolestaan on vuorostaan ensimmäisen leikkauksen ulkopuolelle jäävän alkion indeksi. Sen puuttuessa otetaan mukaan kaikki listan loput alkiot. Sama tulos saataisiin siis myös merkinnällä [0:3].
Leikkauksissa positiivista on se, että niitä ei haittaa listan rajojen ylitys:
In [4]: elukoita[10:15]
Out[4]: []
Samalla nähdään esimerkki leikkauksesta, joka alkaa muualta kuin listan alusta. Leikkausta käyttämällä voimme muokata tulosta-funktion tulostamaan vain 20 ensimmäistä levyä kokoelmasta:
def tulosta(kokoelma):
    for i, levy in enumerate(kokoelma[:20]):
        print(
            f"{i + 1:2}. "
            f"{levy['artisti']}, {levy['albumi']}, {levy['kpl_n']}, "
            f"{levy['kesto']}, {levy['julkaisuvuosi']}"
        )

Rajatarkistus

Listojen kanssa eräs yleinen skenaario on sellainen, jossa listan toisessa tai molemmissa päissä on alkioita joita ei haluta käsitellä. Esimerkiksi datassa voi olla otsikkorivi, tai pelilautaa kuvaavassa 2-ulotteisessa listassa voi olla reunat. Loppupään kanssa on usein edullista käyttää negatiivisia indeksejä, koska tällöin ei esimerkiksi tarvi välittää lainkaan listan pituudesta.
Opittavat asiat:
Listojen
leikkaaminen
ja negatiiviset
indeksit
.

Alustus:
Otetaan esimerkkinä pelikentän riviä kokonaislukuina kuvaava lista, jossa numerot 0-9 ovat peliin liittyviä symboleita ja 10 reunaa. Listan voit määritellä näin:
In [1]: rivi = [10, 0, 1, 1, 1, 0, 1, 2, 2, 1, 10]

Haettu vastaus:
Vastaukseen haetaan koodiriviä, joka tulostaa em. rivi-muuttujan kaikki muut paitsi päädyissä olevat
alkiot
. Kätevin tapa jättää päädyt ulos on käyttää leikkausta. Kirjoita siis sopiva tulostuskomento, jossa hyödynnetään leikkausta. Viimeisen alkion jättämiseen leikkauksen ulkopuolelle kannattaa soveltaa negatiivisia indeksejä, ja itse asiassa sitä myös odotetaan vastaukselta - turha siis laskea mikä on viimeisen alkion indeksi. Negatiivisia indeksejä käyttäessä listan viimeinen alkio on kohdassa -1, toiseksi viimeinen kohdassa -2 jne.
Kirjoita listan leikkaus alla olevaan vastauslaatikkoon.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Lukuja kantamalla

Seuraavien 20
alkion
tulostamiseksi tarvitaan kaksi asiaa:
  1. Pitää selvittää kuinka monta 20 levyn listausta pitää tulostaa (viimeinen voi olla vajaa)
  2. Pitää tehdä
    silmukka
    , joka käydään läpi näin monta kertaa.
Aloitetaan ensimmäisestä ongelmasta. Listan pituuden saa len-funktiolla, mistä voidaan jakolaskun keinoin selvittää, montako 20 alkion kokonaisuutta siitä löytyy. Ongelmaksi jää pyöristys oikeaan tulostusten määrään. Jos levyjä on 20 riittää yksi tulostus, mutta jos niitä on 21 pitää tulostuksia tehdä kaksi. Tarvitaan siis funktio, joka pyöristää aina ylöspäin. Tähän löytyy vastauksena math-
moduulin
ceil-funkio:
def tulosta(kokoelma):
    tulostuksia = math.ceil(len(kokoelma) / 20)
Tätä laskettua tietoa voidaan käyttää hyväksi uuden tulostussilmukan kehittelyssä.
Silmukkaa
tulee siis toistaa laskettu määrä kertoja, ja kullakin
kierroksella
tulostetaan 20 levyä. Silmukka, joka suorittaa sisältönsä määrätyn määrän kertoja, tehdään tyypillisesti tietynlaisella
for-silmukalla
. Siinä läpikäytävä (eli in-operaattorin oikealla oleva) arvo ei ole mikään olemassaoleva
lista
, vaan silmukkaa varten luotu range-objekti. Tämä on
objekti
, joka tuottaa sarjan lukuja halutulta väliltä:
In [1]: luvut = range(10)
In [2]: for luku in luvut:
   ...:     print(luku)
   ...:
0
1
2
3
4
5
6
7
8
9
Luonnollisesti, jos käydään läpi luvut [0, ..., 9], saadaan aikaan kymmenen toistoa. Koodissa range-objekti voidaan laittaa myös suoraan for-silmukan määrittelyriville:
In [1]: for luku in range(10):
   ...:     print(luku)
...
0
1
2
3
4
5
6
7
8
9
Vähemmän yllättäen range-funktion
argumenttina
oleva 10 voidaan myös korvata
muuttujalla
. Tätä tietoa soveltamalla uusi tulosta-funktio alkaa muotoutua:
PER_SIVU = 20

# välistä leikattu muut funktiot

def tulosta(kokoelma):
    tulostuksia = math.ceil(len(kokoelma) / PER_SIVU)
    for i in range(tulostuksia):
        alku = i * PER_SIVU
        loppu = (i + 1) * PER_SIVU
        muotoile_sivu(kokoelma[alku:loppu])
Toiminta perustuu siihen, että lasketaan
listasta
uusi
leikkaus
, jonka aloituspiste on
kierroksen
numero (ensimmäinen kierros on 0) kerrottuna 20:llä ja lopetuspiste kierroksen numero + 1 kerrottuna 20:llä. Näin siis saadaan kätevästi leikkaukset 0:20, 20:40, 40:60 jne. Luku 20 on sijoitettu ohjelman alkuun laitettavaan
vakioon
, jotta koodia on helpompi muuttaa jälkikäteen.
Funktiossa
kutsuttavaan
muotoile_sivu-funktioon voidaan itse asiassa kopioida tulosta-funktion vanha sisältö sellaisenaan. Vaihdetaan tosin kokoelma-
parametrin
nimi kuvaavampaan.
def muotoile_sivu(rivit):
    for i, levy in enumerate(rivit):
        print(
            f"{i + 1:2}. "
            f"{levy['artisti']}, {levy['albumi']}, {levy['kpl_n']}, "
            f"{levy['kesto']}, {levy['julkaisuvuosi']}"
        )
Tällä hetkellä toiminta ei tosin eroa mitenkään aiemmasta, sillä tulostuksesta puuttuu pysähtyminen 20 tulostettavan levyn välein. Muistamme kuitenkin, että input-funktio keskeyttää ohjelman suorituksen kunnes käyttäjä antaa
syötteen
. Tätä tietoa voidaan hyödyntää nytkin:
def tulosta(kokoelma):
    tulostuksia = math.ceil(len(kokoelma) / PER_SIVU)
    for i in range(tulostuksia):
        alku = i * PER_SIVU
        loppu = (i + 1) * PER_SIVU
        muotoile_sivu(kokoelma[alku:loppu])
        if i < tulostuksia - 1:
            input("   -- paina enter jatkaaksesi tulostusta --")
Syöteriviä edeltävä
if-lause
jättää input-funktiokutsun pois kun ollaan päästy viimeisen tulostettavan levyryhmän kohdalle. Alla on esitetty toiminta muuttamalla tulostettavien määrä viideksi (kätevästi PER_SIVU-
vakion
arvoa muuttamalla!), koska esimerkkikokoelmassamme ei ole yli 20 levyä.
Tämä ohjelma ylläpitää levykokoelmaa. Voit valita seuraavista toiminnoista:
(L)isää uusia levyjä
(M)uokkaa levyjä
(P)oista levyjä
(J)ärjestä kokoelma
(T)ulosta kokoelma
(Q)uittaa
Tee valintasi: t
 1. Alcest, Kodama, 6, 0:42:15, 2016
 2. Canaan, A Calling to Weakness, 17, 1:11:17, 2002
 3. Deftones, Gore, 11, 0:48:13, 2016
 4. Funeralium, Deceived Idealism, 6, 1:28:22, 2013
 5. IU, Modern Times, 13, 47:14, 2013
   -- paina enter jatkaaksesi tulostusta --
 1. Mono, You Are There, 6, 1:00:01, 2006
 2. Panopticon, Roads to the North, 8, 1:11:07, 2014
 3. PassCode, Clarity, 13, 49:27, 2019
 4. Scandal, Hello World, 13, 53:22, 2014
 5. Slipknot, Iowa, 14, 1:06:24, 2001
   -- paina enter jatkaaksesi tulostusta --
 1. Wolves in the Throne Room, Thrice Woven, 5, 42:19, 2017
Tee valintasi:

Aina ei tarvitse aloittaa alusta

Silmukan toistojen määrän määrittäminen range-funktiolla on yleistä, mutta sitä voidaan käyttää myös tekemään silmukoita, joissa tarvitaan lukusarja laskutoimituksia varten. Tällöin ei välttämättä haluta nollasta alkavaa lukusarjaa (kuvittele esim. tilanne jossa lukusarjan luvut toimivat jakajana silmukan sisällä). Tässä tehtävässä tutustumme lukusarjojen tuottamiseen rangella.
Opittavat asiat: Lukusarjojen generointi range-
funktiolla
. Range-funktion käyttö
silmukassa
.

Alustus:
Syystä joka ei selkeästikään millään tavalla viittaa seuraavien harjoitusten tehtävään, haluamme tehdä silmukan jossa
silmukkamuuttuja
toimii jakajana. Tällöin on yleensä vähän huono aloittaa nollasta... Silmukan sisällä oleva lauseke näyttää tältä:
In [1]: jaettava = 27
In [2]: # silmukkamäärittely tulee tähän
   ...:    print(jaettava / jakaja)
   ...:

Haettu vastaus:
Vastaukseksi halutaan siis ylläolevaan koodiin sopiva
for-silmukan
määrittely. Sovitaan, että haluamme jakaja-muuttujan saavan arvot 2...12. Tarvitset siis sopivan range-
funktiokutsun
silmukkaasi.
Kirjoita for-silmukan määrittelyrivi, joka käy läpi nämä arvot range-funktiota käyttämällä. Voit valita silmukkamuuttujan nimen itse.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.
Ihan vielä ei mennyt putkeen, koska levyjen järjestysnumerot alkavat nyt joka "sivulla" uudestaan ykkösestä. Tätä varten täytyy vielä salakuljettaa toinen
argumentti
muotoile_sivu-funktiolle: tulostettavan sivun numero.
def muotoile_sivu(rivit, sivu):
    for i, levy in enumerate(rivit):
        print(
            f"{i + 1 + sivu * PER_SIVU:2}. ",
            f"{levy['artisti']}, {levy['albumi']}, {levy['kpl_n']}, "
            f"{levy['kesto']}, {levy['julkaisuvuosi']}"
        )
Tosin tuon indeksimatikan voisi laittaa myös toiseen paikkaan. Enumeratelle kelpaa nimittäin toinenkin argumentti, joka kertoo mistä numerosta numerointi lähtee liikkeelle:
def muotoile_sivu(rivit, sivu):
    for i, levy in enumerate(rivit, sivu * PER_SIVU + 1):
        print(
            f"{i:2}. ",
            f"{levy['artisti']}, {levy['albumi']}, {levy['kpl_n']}, "
            f"{levy['kesto']}, {levy['julkaisuvuosi']}"
        )
Tässä muutos on vielä aika yhdentekevä, mutta jos silmukassa käytettäisiin järjestysnumeroa useammassa kuin yhdessä paikassa, edut ovat aika ilmeisiä. Nyt tarvitsee vielä antaa tälle uudelle sivu-
parametrille
argumentti funktiota kutsuttaessa:
def tulosta(kokoelma):
    tulostuksia = math.ceil(len(kokoelma) / PER_SIVU)
    for i in range(tulostuksia):
        alku = i * PER_SIVU
        loppu = (i + 1) * PER_SIVU
        muotoile_sivu(kokoelma[alku:loppu], i)
        if i < tulostuksia - 1:
            input("   -- paina enter jatkaaksesi tulostusta --")
Yhteen asiaan ei tässä ole sen kummemmin kiinnitetty huomiota, koska sen pitäisi olla tässä vaiheessa selvää, mutta... Huomasitko kuinka molemmissa funktioissa on muuttuja i silmukassa? Koodi toimii ongelmitta, ja syy on jälleen kerran siinä, että tässä on kyseessä kaksi eri i-nimistä muuttujaa eri
näkyvyysalueilla
. Tämä ihan vain muistutuksena jos funktioiden käytön eduista tämä yksi on päässyt unohtumaan.
Tulos näyttää nyt siis halutulta:
 1. Alcest, Kodama, 6, 0:42:15, 2016
 2. Canaan, A Calling to Weakness, 17, 1:11:17, 2002
 3. Deftones, Gore, 11, 0:48:13, 2016
 4. Funeralium, Deceived Idealism, 6, 1:28:22, 2013
   -- paina enter jatkaaksesi tulostusta --
 5. IU, Modern Times, 13, 47:14, 2013
 6. Mono, You Are There, 6, 1:00:01, 2006
 7. Panopticon, Roads to the North, 8, 1:11:07, 2014
 8. PassCode, Clarity, 13, 49:27, 2019
 9. Scandal, Hello World, 13, 53:22, 2014
10. Slipknot, Iowa, 14, 1:06:24, 2001
   -- paina enter jatkaaksesi tulostusta --
11. Wolves in the Throne Room, Thrice Woven, 5, 42:19, 2017

Viimeistely

Tulostukset ovat vielä hieman rumia, ja turhat nollatunnit jäävät näkyviin. Muokataan siis lopuksi uutta muotoile_sivu-funktiota. Muutokset kohdistuvat pelkästään merkkijonon muotoiluun, jolle tehdään muutamia editointeja:
def muotoile_sivu(rivit, sivu):
    for i, levy in enumerate(rivit, sivu * PER_SIVU + 1):
        print(
            f"{i:2}. "
            f"{levy['artisti']} - {levy['albumi']} ({levy['julkaisuvuosi']}) "
            f"[{levy['kpl_n']}] [{levy['kesto'].lstrip('0:')}]"
        )
Muotoilun sapluuna on kirjoitettu uusiksi, ja olemme palauttaneet käyttöön
avainsanat
. Keston kohdalla oleva lstrip poistaa nollatunnit kestosta, mikäli niitä löytää - ja itse asiassa myös nollaminuutit jos levy on tarpeeksi lyhyt (strip-metodin toimintaan kannattaa perehtyä tarkasti!). Lopputulos näyttää jo suorastaan kauniilta:
 1. Alcest - Kodama (2016) [6] [42:15]
 2. Canaan - A Calling to Weakness (2002) [17] [1:11:17]
 3. Deftones - Gore (2016) [11] [48:13]
 4. Funeralium - Deceived Idealism (2013) [6] [1:28:22]
 5. IU - Modern Times (2013) [13] [47:14]
   -- paina enter jatkaaksesi tulostusta --
 6. Mono - You Are There (2006) [6] [1:00:01]
 7. Panopticon - Roads to the North (2014) [8] [1:11:07]
 8. PassCode - Clarity (2019) [13] [49:27]
 9. Scandal - Hello World (2014) [13] [53:22]
10. Slipknot - Iowa (2001) [14] [1:06:24]
   -- paina enter jatkaaksesi tulostusta --
11. Wolves in the Throne Room - Thrice Woven (2017) [5] [42:19]
Sen sijaan koodi itsessään ei välttämättä enää ole kauneimmasta päästä, koska muotoilumerkkijonon sisällä alkaa olla ruuhkaisaa. Tässä kohtaa voi harkita, olisiko vanha
format-metodi
parempi vaihtoehto. Metodin tärkein ero
muotoilumerkkijonoon
on se, että paikanpitimiin sijoitetut arvot täytyy osoittaa erikseen metodin argumenteilla, siinä missä f-merkkijono poimii nimet automaattisesti ohjelman
nimiavaruudesta
. Alla olevassa esimerkissä koodirivejä on kyllä enemmän, mutta itse merkkijono näyttää paljon selkeämmältä.
def muotoile_sivu(rivit, sivu):
    for i, levy in enumerate(rivit, sivu * PER_SIVU + 1):
        print("{i:2}. {artisti} - {albumi} ({vuosi}) [{kpl_n}] [{kesto}]".format(
            i=i,
            artisti=levy["artisti"],
            albumi=levy["albumi"],
            kpl_n=levy["kpl_n"],
            kesto=levy["kesto"].lstrip("0:"),
            vuosi=levy["julkaisuvuosi"]
        ))

Seuraavassa jaksossa...

Ohjelmointrillerin huikeassa päätösluvussa teemme vielä listojen kanssa pari juttua, jotka eivät tähän eepokseen mahtuneet: alkioiden poistaminen ja niiden arvojen muuttaminen. Opimme myös tallentamaan kokoelman ajojen välillä, mikä on varmaan ihan hyvä ominaisuus, jos ohjelmaa ei aio pitää ikuisesti päällä.
Niin ja sellainen pikkudetalji kuin graafisten käyttöliittymien alkeet on myös mahdutettu päätöslukuun...

Loppusanat

Silmukat
ja
listat
muodostavat työkalupakin, jolla pystyy yhdessä aiemmin opittujen asioiden kanssa tekemään käytännössä mitä tahansa. Erityisesti Pythonin listat ovat todella monikäyttöisiä. Mitä enemmän ohjelmoit Pythonilla, sitä useammin tulet huomaamaan, että lista on ratkaisu kohtaamaasi ongelmaan. Silmukat kulkevat usein listojen kavereina, koska ne ovat ainoa keino käydä järkevästi läpi listojen sisältämiä
arvoja
.
Myös se, miten paljon etua on ohjelman jakamisesta
funktioihin
, alkoi näkyä tässä materiaalissa aiempaa selkeämmin. Monikäyttöiset kyselyfunktiot helpottavat huomattavasti ydintoiminnan toteutusta kuin myös tulostamisen sijoittaminen omaksi funktiokseen. Myös ohjelman toimintojen jako omiin funktioihinsa on aiempaa vaikuttavampaa, koska ne todella tekevät erilaisia asioita.
Ylipäätään ohjelman suunnittelu osoittautui tässä materiaalissa entistä tärkeämmäksi. Huomasimme että nykyinenkin ratkaisu olisi voitu tehdä paremmin. Näin käy usein riippumatta siitä, kuinka kokenut koodari on kyseessä, ja kuinka mones iteraatio samasta ohjelmasta on kyseessä.
Kun työkalupakki monipuolistuu, kaikkein oleellisin ohjelmointitaito on lopulta pystyä työskentelemään järjestelmällisesti. Jos aloittaa koodaamaan yhtä osaa ohjelmasta miettimättä lainkaan muita osia, saattaa upottaa itsensä suohon, josta mikään ei pelasta. Tämän materiaalin tiedoilla saa jo vahvan pohjan oman lopputyön suunnitelmalliseen tekemiseen ja sitä seuraavista harjoituksista vielä lisävauhtia.

Kuvalähteet

  1. alkuperäinen lisenssi: CC-BY-NC 2.0 (teksti lisätty)
  2. alkuperäinen lisenssi: CC-BY 2.0 (teksti lisätty)
  3. alkuperäinen lisenssi: CC-BY 2.0 (teksti lisätty)
  4. alkuperäinen lisenssi: CC-BY-SA 2.0
  5. alkuperäinen lisenssi: CC-BY-NC 2.0 (teksti lisätty)
  6. alkuperäinen lisenssi: CC-BY-NC-SA 2.0
  7. alkuperäinen lisenssi: CC-BY 2.0 (teksti lisätty)
  8. alkuperäinen lisenssi: CC-BY 2.0 (teksti lisätty)
?
  1. Kuvaus
  2. Esimerkit
Absoluuttinen polku (absolute path) on käyttöjärjestelmäkäsite, joka kertoo hakemiston "koko osoitteen". Absoluuttinen polku ilmaistaan levyaseman juuresta lähtien joten se ei ole riippuvainen siitä mikä on aktiivinen hakemisto. Absoluuttisia polkuja pyritään yleensä välttämään koodissa, erityisesti jos tarkoitus on tehdä koodia jota joku muukin saattaa käyttää. Toinen käyttäjä ei välttämättä sijoita tiedostoja juuri täsmälleen samanlaiseen hakemistorakenteeseen kuin olet omalla koneellasi tehnyt. Erityisesti jos tiedostosi yleensä asuvat kotihakemistossa, pelkästään absoluuttisessa polussa oleva eri käyttäjänimi sotkee kaiken jonkun muun koneella.
Ajonaikaisesta (engl. run time) puhuttaessa määreenä on se aikaväli, kun ohjelma on käynnissä. Esimerkiksi Pythonissa virheet (syntaksivirheitä lukuun ottamatta) tarkastetaan ajonaikaisesti. Ohjelma saattaa siis olla käynnissä ja toimia tiettyyn pisteeseen saakka, kunnes törmätään käsittelemättömään poikkeukseen – ajonaikaiseen virheeseen (engl. run time error).
  1. Kuvaus
  2. Esimerkit
Alkio (engl. item, element) on listan tai muun tietorakenteen sisältämä yksittäinen arvo. Useimmiten alkioista puhutaan juuri listojen yhteydessä. Tällöin alkiolla on arvon lisäksi paikka eli indeksi, joka kertoo sen sijainnin listassa etäisyytenä listan alusta. Niinpä siis listan ensimmäisen alkion indeksi on 0.
  1. Kuvaus
  2. Esimerkit
Alustamisella (engl. initialize) tarkoitetaan yleisesti jonkin arvon asettamista muuttujalle muuttujan luonnin yhteydessä. Pythonissa ei ole mahdollista luoda muuttujaa, jolla ei ole myös jotain arvoa. Niinpä tyypillisesti käytetäänkin sanamuotoa ”muuttuja alustetaan arvolla x”, millä tarkoitetaan sitä, että muuttuja, joka luodaan, saa luomisen yhteydessä (eikä vasta joskus myöhemmin) arvon x.
  1. Kuvaus
  2. Esimerkit
Argumentti (engl. argument) on funktiokutsussa käytettävä arvo, joka välitetään kutsuttavalle funktiolle. Funktiokutsun alkaessa argumentit sijoitetaan parametreiksi kutsuttuihin muuttujiin, joiden kautta arvoihin pääsee funktion sisällä käsiksi.
Arvo (engl. value) on konkreettista, tietokoneen muistissa sijaitsevaa tietoa, jota käytetään ohjelman suorituksen aikana. Arvoilla on tyyppi ja sisältö; esimerkiksi numero 5 on tyypiltään kokonaisluku, jonka sisältö on 5. Useimmiten arvot liitetään muuttujiin, mutta myös operaatioiden ja funktiokutsujen paluuarvot sekä koodissa sellaisenaan esiintyvät arvot ovat arvoja. Käytännössä siis kaikkea konkreettista mitä ohjelma käsittelee voidaan kutsua arvoiksi.
  1. Kuvaus
  2. Esimerkit
Avain (engl. key) on ikään kuin sanakirjan ”indeksi”, eli sillä valitaan yksittäinen arvo tietorakenteen sisältä. Kutakin avainta vastaa yksi arvo. Avaimina käytetään yleensä merkkijonoja, mutta ne voivat olla mitä tahansa muuntumattomia tietotyyppejä, kuten lukuja tai monikkoja.
  1. Kuvaus
  2. Kurssin avainsanat
Avainsanat (engl. keyword) ovat ohjelmointikielessä kielen käyttöön varattuja sanoja, joilla on erityinen merkitys. Hyvät tekstieditorit tyypillisesti merkitsevät avainsanat muista nimistä eroavalla tavalla (esimerkiksi lihavoinnilla tai tietyllä värillä). Avainsanat ovat yleensä suojattuja, eli samannimisiä muuttujia ei voi luoda. Yleisiä avainsanoja Pythonissa ovat esimerkiksi funktioihin liittyvät def ja return. Avainsanat ovat siis osa ohjelmointikielen kielioppia.
  1. Kuvaus
  2. Esimerkit
Avainsana-argumentti-termiä (engl. keyword argument, lyh. kwarg) käytetään, kun funktio- tai metodikutsussa argumentteja annetaan sijoittamalla niitä parametrien nimiin. Tätä käytetään erityisesti format-metodin yhteydessä: "Hei {nimi}".format(nimi="hemuli"). Toinen yleinen käyttötapaus on silloin, kun kutsutulla funktiolla on paljon valinnaisia argumentteja ja näistä vain osa halutaan määrittää. Avainsana-argumentin käyttö voi myös selkeyttää koodia, erityisesti sellaisten argumenttien kohdalla joille annetaan arvoksi True tai False.
  1. Kuvaus
  2. Esimerkit
Avausmoodilla kerrotaan Pythonille (ja käyttöjärjestelmälle) millä tavalla tiedosto avataan. Tiedosto voidaan avata lukemista tai kirjoittamista varten. Oletuksena, eli jos avausmoodia ei erikseen määritellä, tiedosto avataan lukumoodissa ("r"). Kirjoitusmoodeja on kaksi:
  • "w", eli write, joka kirjoittaa tiedoston sisällön puhtaalta pöydältä hävittäen mahdollisesti aiemmin olemassa olleen saman nimisen tiedoston.
  • "a", eli append puolestaan kirjoittaa olemassaolevan tiedoston loppuun.
Molemmat kirjoitusmoodit luovat tiedoston, jos sitä ei vielä ole olemassa.
Siinä missä UNIX-pohjaiset järjestelmät tuottavat \n-merkkejä rivinvaihdoiksi, Windows tuottaa \r\n-rivinvaihtoja, joissa r on carriage return -merkki. Se on kirjoituskoneiden peruja ja tarkoittaa toimenpidettä, jossa kirjoituspää siirretään takaisin rivin alkuun. Yleisesti ottaen tämä on lähinnä asia, joka on hyvä tietää – Python käsittelee molempia rivinvaihtoja kiltisti.
Data (engl. data) on ohjelmoinnin asiayhteydessä mitä vaan tietoa, joka ei kuitenkaan yleisesti kata itse ohjelmakoodia. Yleensä datasta puhuttaessa tarkoitetaan yksittäisiä literaaliarvoja, muuttujien sisältämää tietoa tai jostain tietolähteestä (kuten tiedostosta tai verkko-osoitteesta) luettua tai sinne kirjoitettua tietoa. Nyrkkisääntönä voi kuitenkin pitää sitä, että koodi ja data ovat eri asioita, ja koodi käsittelee dataa. (Joissain yhteyksissä koodikin lasketaan dataksi, mutta näihin ei tällä kurssilla syvennytä.)
Debuggaus (engl. debugging) tarkoittaa ohjelmointivirheiden – bugien – jäljittämistä ja korjaamista. Bugien jäljille pääsemiseen on monia eri tapoja, joista ehkä hyödyllisimpänä Python tarjoaa ohjelman kaatumisen yhteydessä näytettävät virheviestit. Myös debug-printit ovat tavanomainen keino virheiden paikantamiseen; kyseessä on print-komentojen ripottelu koodiin väliaikaisesti esimerkiksi sen selvittämiseen, mihin asti koodin suoritus pääsee, tai muuttujien arvojen tutkimiseen ajonaikaisesti. Debuggaus on niin oleellinen osa ohjelmointia, että sitä varten on kehitetty myös erikseen työkaluja, joita kutsutaan debuggereiksi. Debuggereihin emme kuitenkaan tällä kurssilla koske.
Pythonissa dokumenttimerkkijono (engl. docstring) on kommentin kaltainen merkintä, mutta sillä on oma erityistarkoituksensa. Dokumenttimerkkijono merkitään yleensä kolmella lainausmerkillä (eli '''dokumentti''' tai """dokumentti""". Jos dokumenttimerkkijono on sijoitettu funktion def-rivin alapuolelle (sisennettynä), siitä tulee funktion dokumentaatio, jonka saa esiin help-funktiolla tulkissa. Samoin kooditiedoston alkuun sijoitettu dokumenttimerkkijono muuttuu moduuliin dokumentaatioksi. Dokumenttimerkkijonossa on hyvä kertoa funktion toimintaperiaate sekä selittää mitä sen parametrit ja paluuarvot ovat.
Dokumenttimerkkijonoja ei tule käyttää kommenttien sijasta! Muualla kuin edellä mainituissa paikoissa kommentointiin tulee käyttää kommentteja (eli #-merkillä alkavia rivejä)
  1. Kuvaus
  2. Esimerkit
Ehto-nimitystä (engl. condition) käytetään tällä kurssilla ehtolauseiden ja while-silmukoiden siitä osasta, joka määrittelee milloin lause on tosi ja milloin epätosi. Ehtoa on siis kaikki joka on ehtolauseen aloittavan avainsanan (if tai elif) ja sen päättävän kaksoispisteen välissä.
  1. Kuvaus
  2. Esimerkit
Ehtolause (engl. conditional statement) on yksittäisen ehdon määrittelevä rivi koodissa, jota seuraa sisennetty koodilohko, joka määrittää miten ehdon toteutuessa tulee toimia. Varsinaisia ehtolauseita ovat if- ja elif-lauseet, joista jälkimmäinen ei voi esiintyä ilman ensimmäistä. Toisiinsa liitetyt ehtolauseet muodostavat ehtorakenteita. Ehtolause päättyy aina kaksoispisteeseen, ja tämän kaksoispisteen jälkeen on seurattava vähintään yksi sisennetty koodirivi.
  1. Kuvaus
  2. Esimerkit
Ehtorakenne (engl. conditional structure) on yhdestä tai useammasta toisiinsa liitetystä ehtolauseesta muodostuva rakenne, joka haarauttaa ohjelman suoritusta. Useimmissa ehtorakenteissa on vähintään kaksi haaraa: if ja else. Näiden välissä voi olla myös mielivaltainen määrä elif-lauseilla aloitettuja haaroja. On myös mahdollista, että ehtorakenteessa on pelkkä if-lause. Ehtorakenteessa kussakin haarassa on suoritettavaa koodia, joka kuvaa miten ohjelman tulee ehdon määrittelemässä tilanteessa toimia.
Kokonaisuudessaan ehtorakenne käydään läpi siten, että ensin tarkistetaan järjestyksessä ensimmäisen, eli if-lauseen, ehdon paikkansapitävyys. Jos ehto evaluoitui totuusarvoon True, ohjelman suoritus jatkuu kyseisen if-lauseen lohkosta, jonka suorituksen jälkeen siirrytään koko lopun ehtorakenteen ohi. Jos ehto taas evaluoitui Falseksi, käydään järjestyksessä ehtolauseita läpi toistaen samaa kuin ensimmäisen if-lauseen kohdalla, ja jos mikään ehto ei ollut paikkansapitävä, suoritetaan else-lauseen lohko.
Epätosi (engl. false) on toinen kahdesta mahdollisesta totuusarvosta ja toisen, eli toden, vastakohta. Sitä voidaan pitää lopputuloksena loogisissa ja vertailuoperaatorioissa, jotka eivät pidä paikkansa. Esimerkiksi vertailuoperaatio 5 < 4 ei pidä paikkansa, joten kyseinen operaatio evaluoituu epätodeksi. Pythonissa epätotta merkitään avainsanalla False.
  1. Kuvaus
  2. Esimerkit
Erotin (engl. separator) on merkkijonoihin ja tekstitiedostoihin liittyvä termi. Sillä tarkoitetaan tiettyä merkkiä, joiden kohdilta merkkijono on tarkoitus katkaista, kun se luetaan koodiin. Esimerkiksi, jos merkkijono sisältää tietoja, jotka on tarkoitus lukea listaan, erotin erottelee merkkijonon osat alkioiksi. Koodissa käytetään usein merkkijonojen split-metodia näissä tilanteissa – metodilla voidaan siis pätkiä erottimien kohdilta merkkijono listaksi.
Evaluointi (engl. evaluation) tarkoittaa lausekkeen tai muuttujan arvon lopputuloksen määrittämistä. Suoritettaessa lauseet evaluoituvat joksikin tietyksi arvoksi.
Exception on yleisimpien poikkeusten pääluokka. Kutsumme sitä Pokémon-poikkeukseksi, koska jos sitä käyttää try-except-rakenteessa, except ottaa kiinni kaikki poikkeukset. Tämä ei ole hyvä asia, koska se tekee vikatilanteiden tulkitsemisen vaikeammaksi sekä ohjelman käyttäjälle, että koodarille itselleen – se ottaa nimittäin kiinni myös ohjelmointivirheet, jolloin et saa mitään hyödyllistä tietoa ohjelman kaatuessa.
  1. Kuvaus
  2. Esimerkit
  3. Parametrien valinta
Merkkijonojen format-metodi on Pythonissa tehokas tapa sisällyttää muuttujien arvoja tulostettavaan tai tallennettavaan tekstiin. Merkkijonoon määritetään paikanpitimiä (esim: {:.2f}) joihin sijoitetaan format-metodin argumentit. Esimerkki: "Aasin korvien väli on {:.2f} tuumaa".format(mittaus).
Huom: format on vanhentunut tapa yleiseen merkkijonojen muotoiluun, nykyisin käytetään enemmän f-merkkijonoja. Vanhemmalla formatilla on kuitenkin edelleen käyttönsä.
  1. Kuvaus
  2. Esimerkit
Funktio (engl. function) on ohjelmassa oleva itsenäinen kokonaisuus, joka muodostuu määrittelyrivistä (def-lauseella) sekä funktion suoritettavista koodiriveistä. Funktioita käytetään selkeyttämään ohjelman rakennetta sekä koodin toiston välttämiseen. Funktiot kommunikoivat keskenään ja pääohjelman kanssa funktion parametrien sekä paluuarvojen välityksellä. Funktion sisällä määritetyt muuttujat (ml. parametrit) ja muut nimet ovat olemassa ainoastaan funktion sisällä. Vastaavasti funktioiden ei pitäisi lukea arvoja itsensä ulkopuolelta.
  1. Kuvaus
  2. Esimerkit
Funktiokutsu (engl. function call) on menetelmä, jonka seurauksena ohjelman suoritus ”hyppää” toiseen kohtaan koodia – sen funktion alkuun, jota kutsutaan. Funktiota kutsuttaessa sillä annetaan sulkeissa argumentit, joihin funktiolohkon koodista käsin pääsee käsiksi funktiomäärittelyn vastaavista kohdista löytyvien parametrien kautta. Funktion suoritus päättyy, kun törmätään funktion loppuun tai return-lauseeseen. Tällöin ohjelmakoodin suoritus palaa takaisin edelliseen kohtaan, eli sinne, mistä funktiota kutsuttiin, ja funktiokutsu korvautuu funktion paluuarvolla.
Toisin sanoen kutsumalla saadaan yksi ohjelman osa käyttämään toista – esimerkiksi pääohjelma funktiota tai funktio toista funktiota.
  1. Kuvaus
  2. Esimerkit
Funktioiden määrittely tapahtuu def-lauseella, jonka yhteydessä annetaan nimi funktiolle sekä sen parametreille. Kaikkien näiden valinta on oleellinen osa hyvän ja yleiskäyttöisin funktion kirjoittamista. Nimi tulisi valita siten, että se kuvaa mahdollisimman hyvin mitä funktio tekee - vastaavasti parametrien nimien tulisi olla sellaisia, että niistä voi helposti päätellä millaiset argumentit funktiolle pitää antaa. Funktion varsinainen koodi määritetään sisennettynä def-rivin alle. Funktion koodi voi ja usein sisältääkin useita rivejä - se voi myös sisältää muita sisennyksiä (esim. ohjausrakenteita).
  1. Kuvaus
  2. Esimerkit
Generaattori (engl. generator) on erityinen objektityyppi, joka toimii esimerkiksi for-silmukassa listan tavoin. Generaattori ei kuitenkaan ole muistissa oleva kokoelma arvoja, vaan erityinen funktio, joka tuottaa arvoja laiskasti, eli sitä mukaa kuin sitä käydään läpi. Tästä johtuen generaattorin ”sisältöä” ei ole mahdollista tulostaa, eikä siitä voida valita alkioita indeksiosoituksella. Generaattorit eivät kuulu alkeiskurssin aihepiiriin.
  1. Kuvaus
  2. Esimerkit
  3. Tilasanakirjat
Globaali muuttuja (engl. global variable) on pääohjelman tasolla esitelty muuttuja, jota muokataan suoraan funktiossa tuomatta sitä funktion nimiavaruuteen parametrin kautta. Globaalien muuttujien käyttö on huonoa ohjelmointityyliä, ja niiden sijaan tietoa kuuluisikin kuljettaa funktioille argumentteina ja ottaa funktiolta vastaan paluuarvoina muutettuja arvoja. Näin tekemällä välttää niin kutsutun globaalin tilan, joka huonontaa koodin ymmärrettävyyttä.
Globaali näkyvyys koskee kaikkia nimiä (muuttujat, funktiot jne.) jotka on määritelty pääohjelman tasolla. Kaikki nimet jotka kuuluvat globaalin näkyvyyden piiriin ovat luettavissa mistä tahansa ohjelmakoodissa. Niihin ei voi kuitenkaan sijoittaa uusia arvoja muualla kuin pääohjelmatasolla. Yleisesti ottaen globaalilta näkyvyysalueelta tulisi käyttää funktioiden sisällä vain vakioita ja muita funktioita. Varsinaiset pääohjelman muuttujat pitäisi aina siirtää funktioihin parametrien kautta.
Haara (engl. branch) on yksi keskenään vaihtoisista reiteistä, joita pitkin ohjelman suoritus voi tietystä pisteestä lähtien edetä. Esimerkiksi ehtorakenteissa jokainen if-, elif- ja else-lohko haarauttaa ohjelman suorituksen.
  1. Kuvaus
  2. Esimerkit
Hypystä (engl. jump) puhuttaessa tarkoitetaan ohjausrakenteen aiheuttamaa siirtymistä, jonka jälkeen ohjelman suoritus jatkuukin jostain muualta kuin seuraavalta koodiriviltä.
  1. Kuvaus
  2. Esimerkki
Ikuinen silmukka tai ikisilmukka (engl. infinite loop) on silmukka, joka ei pääty ikinä – silmukan alaisuuteen kuuluvaa koodia siis toistetaan ”ikuisesti”. Ikisilmukoilla on ohjelmoinnissa käyttötarkoituksensa, mutta silloin tällöin tahattomasti syntynyt ikisilmukka voi myös olla ohjelman jumiutumisen aiheuttava bugi. Pythonissa ikuiset silmukat onnistuvat pääasiassa while-silmukoilla.
  1. Kuvaus
  2. Esimerkit
Indeksi (engl. index) on kokonaislukuarvo, joka osoittaa alkion sijainnin järjestetyssä tietorakenteessa (lista, monikko, mutta myös merkkijono!). Indeksit alkavat nollasta, joten viimeinen indeksi on (rakenteen pituus - 1). Tätä voi ajatella etäisyytenä rakenteen alusta. Python tuntee myös negatiiviset indeksit, jolloin indeksi -1 viittaa aina viimeiseen alkioon, -2 toiseksi viimeiseen jne. Kun rakenteesta otetaan alkio indeksin perusteella, puhutaan usein osoittamisesta.
  1. Kuvaus
  2. Esimerkit
Kun käytetään tietorakenteen, esimerkiksi listan, indeksiä, puhutaan (indeksi)osoittamisesta. Tämä osoittaminen merkitään hakasuluilla, esim. arvosanat[0]. Indeksiosoitus palauttaa alkion. Osoitus listan ulkopuolelle aiheuttaa IndexError-poikkeuksen, ja on hyvä pitää mielessä että listan viimeinen indeksi on sen pituus - 1 (koska indeksointi alkaa nollasta). Indeksi voi olla myös negatiivinen, jolloin laskenta alkaa listan lopusta (eli -1 on listan viimeinen alkio).
Katso myö: leikkaus.
Jäsenarvo (engl. attribute) on objektille kuuluva arvo, eli ominaisuus eli attribuutti. Se on siis nimi, joka kuuluu objektin sisäiseen nimiavaruuteen, ja siihen päästään käsiksi objektin kautta: aika.tm_hour joka antaisi aika-objektista tunnit.
Kierros (engl. iteration) on toistorakenteiden eli silmukoiden yhteydessä käytetty sana. Kierroksella viitataan siihen, kun silmukan alla sijaitseva koodi suoritetaan kertaalleen alusta loppuun – tämä on siis yksi kierros.
Kirjasto (engl. library) tai moduuli (engl. module) (kuten niitä Pythonissa virallisesti kutsutaan) on valmiiksi kirjoitettua koodia, jolla on oma rajattu tarkoituksensa. Tyypillisesti kirjasto sisältää ainakin nipun aihepiiriinsä kuuluvia funktioita, mutta voi sisältää muutakin (esim. luokkia tai vakioita). Esimerkiksi Turtle on kirjasto, jonka tarkoitus on tarjota helposti käytettäviä piirtofunktioita.
  1. Kuvaus
  2. Materiaaliesimerkki
  3. Peruskäyttö
Komentoriviargumentti (engl. command line argument) tai -parametri on nimitys lisätiedolle, joka annetaan komennon yhteydessä kun ohjemaa käynnistetään komentoriviltä. Komentoriviargumentit erotetaan toisistaan tyypillisesti välilyönnillä. Esimerkiksi komennossa python koodi.py koodi.py on itse asiassa komentoriviargumentti. Komentoriviargumentteja voi käsitellä Python-koodissa sys-moduulin argv-muuttujan kautta.
  1. Kuvaus
  2. Esimerkit
Kommentti (engl. comment) on kooditiedostossa olevaa tekstiä, joka ohitetaan kun koodia suoritetaan. Kussakin kielessä on oma tapansa sille miten rivi merkitään kommentiksi. Pythonissa se on #- eli risuaitamerkki (engl. hash character), jonka jälkeen riviltä löytyvän tekstin Python-tulkki ohittaa kokonaan. Kommenteilla voi selventää koodin lukijalle (tai itselleen) mitä koodissa tapahtuu. Yleensä kommentit on hyvä laittaa omille riveilleen kommentoitavan koodin yläpuolelle.
Ohjelman ja sen funktioiden toiminta kuvataan yleensä mieluiten dokumenttimerkkijonossa. Kommentteja käytetään enemmänkin välihuomioiden tekemiseen.
Toinen tapa käyttää kommentteja on tilapäisesti kommentoida rivejä pois esimerkiksi vaihtoehtoisen koodin testaamiseksi. Tällöin aiempaa koodia ei tarvitse poistaa – kätevää, jos myöhemmin osoittautuu, että sitä tarvitaan sittenkin.
Kooditiedosto (engl. code file) on tekstimuotoinen tiedosto, joka sisältää suoritettavaa koodia. Python-kooditiedosto suoritetaan komentokehotteesta kirjoittamalla python koodi.py, jossa koodi.py on tiedoston nimi. Kooditiedostoa suorittaessa yksittäisten rivien paluuarvot eivät tule näkyviin – ainoastaan print-funktiolla tulostettavat tiedot näkyvät käyttäjälle.
Ohjelman käyttämät arvot ovat kovakoodattuja (engl. hard coded) silloin, kun ne esiintyvät literaaliarvoina – eli semmoisenaan – ohjelman lähdekoodissa sen sijaan, että ne selvitettäisiin ajonaikaisesti esimerkiksi kysymällä käyttäjältä tai lukemalla tiedostosta.
Kutsupyyntö (eng. callback) on erityisesti nykyaikaisessa ohjelmoinnissa yleinen mekanismi, jossa toiselle - usein jonkun muun tekemälle - ohjelman osalle annetaan funktio, jota sen tulee kutsua toimintansa aikana. Jos tavallinen funktiokutsu vastaa puhelinsoittoa, kutsupyyntö on loogisesti soittopyyntö. Jos ohjelman osa käyttää kutsupyyntöä, sen dokumentaatio tyypillisesti kertoo, millaisen funktion sille voi antaa - erityisesti mitä parametreja funktiolla voi olla ja millainen arvo sen tulee palauttaa.
Käsittelijä(funktio) (engl. handler) on funktio, joka on kiinnitetty tapahtumaan siten, että sitä kutsutaan kun tarkkailtu tapahtuma havaitaan. Tämä johtaa siihen, että yleensä käsittelijää ei kutsuta samassa koodissa missä se on määritelty, vaan se toimii takaisinkutsuna. Käsittelijät liittyvät yleensä käyttöliittymä- ja pelikirjastoihin, joissa ohjelman pääsilmukka pyörii kirjaston sisällä ja tarkkailee tapahtumia. Käsittelijät ovat varsinaisen sovelluksen tapa toteuttaa omat toimintonsa tapahtumien kautta. Koska sovelluksen kirjoittaja ei voi vaikuttaa siihen miten käsittelijäfunktiota kutsutaan, sen parametrien ja paluuarvojen tulee vastata kirjaston antamia määrityksiä.
Käyttöliittymä (engl. User Interface, lyh. UI) on rajapinta ohjelman ja ohjelman käyttäjän – tyypillisesti ihmisen – välillä. Yksinkertaisessa tekstipohjaisessa käyttöliittymässä käyttäjältä voidaan pyytää ohjelman suoritusta varten tietoa input-funktiokutsujen avulla. print-funktiolla voidaan puolestaan esittää käyttäjälle tietoa ja lopputuloksia.
Monet loppukäyttäjälle interaktiiviseen käyttöön tarkoitetut ohjelmat toimivat jonkinlaisen graafisen käyttöliittymän (engl. Graphical User Interface, lyh. GUI) kautta. Näihin sisältyy yleensä ikoneita, painikkeita, avattavia valikoita ynnä muita hiirellä tai kosketusnäytöllä tökittäväksi tarkoitettuja käyttöliittymäelementtejä. Tällä kurssilla tutustumme lopputyön yhteydessä pintaa raapaisemalla graafisten käyttöliittymien sielunelämään.
Käyttöliittymäelementti (engl. UI element, widget) on jokin (yleensä graafiselle) käyttöliittymälle ominainen komponentti, jonka kautta käyttäjän vuorovaikutus ohjelman kanssa on mahdollista. Tällaisia ovat esimerkiksi napit, valikot, liukusäätimet ynnä muut.
Lause (engl. statement) on ohjelmointikielessä nimitys yksittäiselle suoritettavalle asialle, joka on yleensä yksi koodirivi.
Lauseke (engl. expression) tarkoittaa ohjelmoinnissa evaluoitavaa yksikköä. Esimerkiksi 5 + 5 ja "aasi" != "apina" ovat lausekkeita, jotka evaluoituvat arvoiksi 10 ja True. Lauseke yksin ei muuta ohjelman tilaa mitenkään, ellei sillä ole sivuvaikutuksia. Sen sijaan lauseke vaikuttaa osana lausetta.
  1. Kuvaus
  2. Esimerkit
Leikkaamisella (engl. slice) tarkoitetaan sitä, kun sekvenssistä (yleensä listasta, mutta myös merkkijonoista) otetaan osasekvenssi. Lopputuloksena on samaa tyyppiä oleva arvo, joka on kopio valitusta alueesta. Valinnassa merkitään aloitus- ja lopetusindeksit. Molemmat ovat tosin valinnaisia. Leikkaus merkitään sivu = kokoelma[5:10] joka ottaisi siis alkiot indekseistä 5…9. Kaksoispisteen jälkeinen luku on ensimmäinen indeksi jota ei oteta mukaan!
Leikkaaminen ei koskaan aiheuta IndexErroria!
  1. Kuvaus
  2. Esimerkit
Lista (engl. list) on järjestetty kokoelma arvoja, joka on Python-ohjelmoinnissa todellinen monitoimikone. Lista voi sisältää mitä tahansa arvoja, eikä sen kokoa tarvitse tuntea ennalta.
Listassa olevia arvoja kutsutaan alkioiksi. Jokaisella alkiolla on listassa paikka, jota kutsutaan indeksiksi. Indeksit alkavat nollasta! Kaiken tämän lisäksi lista on luonteeltaan muuntuva tietotyyppi. Kaikesta tästä on kerrottu hyvin paljon kolmosmateriaalissa.
Lista voi myös sisältää muita listoja. Tällä tavalla muodostettua tietorakennetta kutsutaan kaksiulotteiseksi listaksi (engl. two-dimensional list). Tietenkin sisäkkäisiä listoja (engl. nested list) voi olla kahtakin tasoa syvemmälle, jolloin ulottuvuuksien lukumäärä kasvaa vastaavasti. Tällöin puhutaan moniulotteisista listoista (engl. multidimensional list).
Literaaliarvo (engl. literal) on yleisnimitys arvoille jotka esiintyvät koodissa sellaisenaan. Arvo ei siis ole muuttujassa, vaan se on kirjoitettu koodiin. Esimerkiksi lauseissa x = 5 ja print("aasi"), 5 ja "aasi" ovat literaaliarvoja. Termiä käytetään pääasiassa yksinkertaisten muuttujatyyppien eli lukujen, totuusarvojen ja merkkijonojen kanssa.
  1. Kuvaus
  2. Muunnokset
Liukuluku (engl. floating point number, lyh. float) on tietokoneiden käyttämä desimaaliluvun approksimaatio. Tietokoneet eivät arkkitehtuurinsa vuoksi pysty käsittelemään oikeita desimaalilukuja, joten niiden tilalla käytetään liukulukuja. Liukuluvut saattavat aiheuttaa pyöristysvirheitä - tämä on hyvä pitää mielessä niitä käyttäessä. Pythonissa on olemassa decimal-moduuli, joka pystyy käsittelemään desimaalilukuja tarkasti.
Lohko (engl. block) on nimitys joukolle koodirivejä jotka kuuluvat yhteen. Lohkoa yhdistää se, että rivit ovat samalla sisennystasolla (tosin lohko voi sisältää myös muita lohkoja). Tyypillisiä lohkoja ovat esim. ehtorakenteiden suoritettavat osat, eli ne sisennyt koodirivit jotka seuraavat ehtoa / elseä. Lohko tulkitaan päättyneeksi kun vastaan tulee rivi, jonka sisennystaso on pienempi kuin lohkoon kuuluvien rivien.
  1. Kuvaus
  2. Lisätietoa
Looginen operaattori (engl. boolean operator) viittaa Boolen algebran operaatiohin, joissa käsitellään totuusarvoja. Tyypillisiä loogisia operaatioita ovat ehtolauseista tutut and, not ja or. Näistä and on tosi jos ja vain jos molemmat operandit ovat tosia; or on tosi jos ainakin toinen operandeista on tosi; ja not on tosi, jos sen ainoa operandi on epätosi.
Lähdekoodi – lyhemmin koodi – (engl. source code, code; alan slangi sorsa) tarkoittaa tekstiä, joka on kirjoitettu ohjelmointikielellä.
Merkillä (engl. character) tarkoitetaan ohjelmoinnissa yksittäistä datana esiintyvää kirjainta, numeroa, välimerkkiä tai muuta vastaavaa symbolia. Pythonissa merkki edustaa pienintä merkkijonon yksittäistä palasta.
  1. Kuvaus
  2. Esimerkit
Merkkijono (engl. string) on tietotyyppi, joka sisältää tekstiä. Sitä käytetään erityisesti käyttäjän kanssa viestimiseen. Merkkijonojen sisältöä voidaan myös tallentaa tiedostoihin. Pythonissa merkkijono merkitään lainaus- tai heittomerkillä (esimerkiksi "aasi" tai 'aasi'). Suosimme ensimmäistä. Merkkijono voidaan merkitä myös kolmella merkillä jolloin se voi olla monirivinen – tätä käytetään erityisesti dokumenttimerkkijonojen (docstring) kanssa. Merkkijono on muuntumaton tietotyyppi – kaikki, mikä näennäisesti muokkaa merkkijonoa, tosiasiassa luo (ja palauttaa) siitä muutetun kopion.
  1. Kuvaus
  2. Esimerkit
Metodi (engl. method) on funktio, joka on osa objektia eli objektin ominaisuus, jolla objekti usein muuttaa omaa tilaansa. Metodia kutsuttaessa käsiteltävä objekti tulee kutsun eteen: valinta.lower(). Metodeita kutsutaan myös joskus jäsenfunktioiksi (engl. member function).
Metodikutsu (engl. method call) vastaa toiminnaltaan funktiokutsua. Merkittävänä erona kuitenkin käsiteltävä objekti on metodikutsun edessä siinä missä funktiokutsussa se annettaisiin argumenttina. Metodikutsussa siis objekti tyypillisesti käsittelee itseään. Esimerkiksi sana.upper() on metodikutsu, jossa käsitellään sana-muuttujan viittaamaa objektia.
Moduuli (engl. module) on periaatteessa mikä tahansa Python-kooditiedosto. Yleisemmin kuitenkin moduulista puhutaan kirjaston synonyymina. Tyypillinen moduuli sisältää yhteen asiaan keskittyviä funktioita ja mahdollisesti muutakin (esimerkiksi vakioita ja luokkia). Laajat ohjelmat on usein myös jaettu useisiin moduuleihin siten että kukin moduuli keskittyy ohjelman toiminnan tiettyyn osa-alueeseen.
  1. Kuvaus
  2. Esimerkit
Monikko (engl. tuple) on ns. jäädytetty lista. Se on siis järjestetty kokoelma arvoja kuten listakin, mutta se on muuntumaton objekti - sen sisältöä ei siis voi muuttaa muuten kuin luomalla uuden kopion. Monikkoja voidaan siis ainoastaan luoda uusia ja lukea. Monikko merkitään yleensä kaarisulkeilla: (1, 2, 3), mutta myös pelkkä 1, 2, 3 on monikko.
Toisin kuin lista, monikko voi toimia sanakirjan avaimena.
  1. Kuvaus
  2. Esimerkit
Pythonissa objektit erotellaan muuntuviin ja muuntumattomiin. Muuntumaton (engl. immutable) arvo on sellainen, jonka sisältö ei voi muuttua - kaikki operaatiot jotka näennäisesti muuttavat arvoa tosiasiassa luovat siitä uuden kopion, joka yleensä sijaitsee uudessa muistipaikassa. Esimerkiksi merkkijonot ovat tyypillinen muuntumaton tyyppi Pythonissa. Siksi merkkijonojen kanssa näkee yleensä jotain tällaista: valinta = valinta.lower()
  1. Kuvaus
  2. Esimerkit
Pythonin objekteissa on kahta tyyppiä: muuntuvia ja muuntumattomia. Muuntuvat (engl. mutable) objektit ovat sellaisia, joiden arvo voi muuttua suorituksen aikana esim. metodikutsun seurauksena. Yleisin esimerkki muuntuvista objekteista on lista: muumilaakso.append("Hemuli") muuttaa muumilaakso-nimistä listaa pysyvästi lisäämällä siihen uuden arvon. Kaikki listaan viittaavat lauseet ohjelmassa käsittelevät tästä eteenpäin listaa, johon "Hemuli" on lisätty.
Yksinkertaistettu tapa käsittää muuttuja (engl. variable) on ajatella sitä tietovarastona – muuttuja sisältää jotain. Tätä ilmaisua käytetään usein puheessa, mutta se ei ole täysin tarkka. Tarkempi kuvaus on, että Python-muuttuja on viittaus arvoon. Se on siis yhteys muuttujan nimen ja tietokoneen muistissa olevan arvon välillä. Muuttuja ei siis varsinaisesti sisällä arvoa – se ainoastaan sisältää tiedon siitä mistä arvo löytyy.
Ohjelmointikielissä on oleellista ymmärtää määrittelyn (engl. definition) ero suorittamiseen. Määrittelemällä luodaan kuvauksia funktioista, muuttujista ja erilaisista tietorakenteista – tavallaan siis kerrotaan ohjelmointikieltä käyttäen, minkälainen jokin edellä mainituista asioista on, tai mitä sen kuuluisi tehdä. Pythonissa määrittelyn ja suorittamisen ero on helpoin ymmärtää funktioiden avulla. Funktiomäärittelyssä funktio vasta luodaan – ikään kuin tehtaalla koottu laite. Funktiota varsinaisesti käytetään – eli sen toiminnallisuus hyödynnetään funktiota varten määriteltyä koodia ajamalla – vasta funktiokutsun yhteydessä. Samaa vertausta käyttäen funktiokutsu vastaa siis sitä hetkeä, kun tehtaalta saapunut laite käynnistetään.
  1. Kuvaus
  2. Esimerkit
Nimeämätön vakio tai taikaluku (engl. magic number) on koodissa esiintyvä literaaliarvo, jota ei selitetä millään tavalla. Hyvään ohjelmointityyliin kuuluu taikalukujen välttäminen. Oikea – itsedokumentoiva – tapa on nimetä koodissa esiintyvät vakiot muuttujiin, jolloin niiden muuttaminen onnistuu tarpeen tullen yhdestä paikasta yhdellä muutoksella, ja koodin lukijan on helpompi ymmärtää koodia.
  1. Kuvaus
  2. Nimeämiskäytännöt
Muuttujilla, funktioilla, vakioilla, moduuleilla ja muilla vastaavilla on kullakin nimi (engl. identifier) – se osa lähdekoodia, joka tarkoittaa kyseistä asiaa. Esimerkiksi, jos ohjelmoija määrittelee koodin alussa muuttujan leveys arvolla 15, kyseisellä leveys-nimellä voidaan myöhemmin käyttää kyseistä muuttujaa. Nimen voidaan siis ajatella olevan ohjelmoijan ja koodia lukevan tulkin yhteinen ymmärrys siitä, mihin asioihin lähdekoodissa esiintyvät sanat viittaavat. Nimet kuuluvat aina johonkin nimiavaruuteen.
Nimiavaruus (engl. namespace) on joukko nimiä (muuttujia, vakioita, funktioita jne.) jotka kuuluvat samaan kontekstiin. Esimerkiksi funktion sisällä, eli funktiomääritelmän lohkossa on oma nimiavaruus: funktion sisällä määritetyt nimet ovat käytössä ainoastaan sen sisällä. Ohjelmalla on myös aina päänimiavaruus (engl. global namespace), jossa kaikki pääohjelmassa määritetyt nimet sijaitsevat. Tavallista import-lausetta käytettäessä saadaan niin ikään erillinen nimiavaruus, johon päästään käsiksi moduulin nimen kautta – moduulin sisäiset nimet ovat siis tällöin erillisessä avaruudessa. Katso myös näkyvyysalue.
Nimikonflikti syntyy, jos useammalle kuin yhdelle arvolle koitetaan antaa sama nimi. Tällöin tapahtuu niin, että tuoreempi sijoitus jåä voimaan. Tästä seuraa yleensä ohjelman kaatavia virheitä, koska usein arvot ovat eri tyyppiä. Voi jopa käydä niin, että epämääräisesti nimetyn funktion päälle tallennetaan vahingossa saman niminen muuttuja.
  1. Kuvaus
  2. Esimerkit
Näkyvyysalue (engl. scope) määrittää sen, onko jokin tietty nimi (muuttuja, funktio tms.) käytettävissä tietyssä kohdassa ohjelmaa. Esimerkiksi funktiomääritelmän lohkossa voidaan viitata funktiossa määriteltyihin muuttujiin, koska ne ovat funktion näkyvyysalueella. Sen sijaan muut funktiot eivät voi viitata näihin muuttujiin, koska ne kuuluvat eri näkyvyysalueelle. Globaalin (ts. pääohjelman) näkyvyysalueen nimet ovat luettavissa kaikkialla koodissa.
  1. Kuvaus
  2. Syventävää nippelitietoa
Näppäimistökeskeytyksellä (engl. keyboard interruption) voi pakottaa jumiin jääneen ohjelman sammumaan. Sen saa aikaan painamalla Ctrl+C sen terminaalin ollessa auki, jossa ohjelma pyörii. Pythonissa näppäimistökeskeytyksen saa käsiteltyä kaappaamalla KeyboardInterrupt-poikkeuksen try-except-rakenteella.
Objekti (engl. object), joskus myös olio, on Pythonissa yleistä terminologiaa. Kutsumme objekteja pääasiassa arvoiksi alkeiskurssilla, mutta Pythonissa kaikkea voi käsitellä objekteina. Tämä tarkoittaa, että mihin tahansa voidaan viitata muuttujilla (esimerkiksi funktion voi sijoittaa muuttujaan). Tämän kurssin puitteissa objekti-termiä käytetään sellaisista arvoista joilla on metodeja.
Objektit nousevat merkittävämpään rooliin alkeista eteenpäin, erityisesti koodissa jossa käytetään luokkia.
Ohjausrakenne (engl. control structure) on yleisnimitys ohjelmointikielen sallimista keinoista, jotka hallitsevat jollain tavalla ohjelman suorituksen kulkua. Näihin rakenteisiin lukeutuvat kurssin puitteissa ehtorakenteet, toistorakenteet sekä poikkeusten käsittely.
Ohjelmointiongelma on ohjelmointityön kohde. Se on siis jokin todettu tarve, jota varten ohjelmaa koodataan. Tarve voi olla jonkin tietokoneella tehtävän asian automatisointi, verkkosivun pystyttäminen tai ihan vain hauskan pelin tekeminen.
Ohjelmointityyli (engl. programming style) on joukko ohjeita tai tapoja, joita ohjelmoija noudattaa koodia kirjoittaessaan. Näihin tapoihin lasketaan muun muassa sisennyksen syvyys, muuttujien ja funktioiden nimeämiskäytännöt, välilyöntien käyttö lauseissa sekä monet muut tyyliseikat. Ohjelmointityylejä on useita erilaisia, ja tällä kurssilla opetetaan noudattamaan tiettyjä tyyliin liittyviä sääntöjä.
Ohjelmointivirhe eli bugi (engl. bug) on virhe ohjelman lähdekoodissa. Bugien seurauksena ohjelma ei välttämättä käynnisty ollenkaan, kaatuu, voi joissain tilanteissa toimia väärin ja joskus aiheuttaa jopa erittäin vakavia tietoturvaongelmia. Huolellinen ohjelmointi ja testaaminen – myös harvinaisilla nurkkatapauksilla – vähentää bugien todennäköisyyttä. Ohjelman havaitun virheellisen toiminnan aiheuttavan koodin etsimistä ja korjaamista kutsutaan debuggaukseksi.
Oletusarvo (engl. default value) on arvo, joka annetaan funktion valinnaisella parametrille mikäli sitä vastaavaa argumenttia ei annettu funktiota kutsuttaessa. Esimerkiksi def kysy_pituus(kysymys, maksimi=10): -määrittelyrivillä maksimi on valinnainen parametri, jonka oletusarvo on 10.
Ominaisuus (attribute) liittyy objekteihin siten, että objekteilla voidaan sanoa olevan ominaisuuksia. Tällä kurssilla useimmat näistä ominaisuuksista ovat metodeja, mutta ne voivat olla myös arvoja. Objektin ominaisuutta käsitellään notaatiolla, jossa objektin nimen ja ominaisuuden nimen väliin tulee piste, esim: valinta.lower()-metodikutsussa valinta on objekti ja lower on ominaisuus.
  1. Kuvaus
  2. Esimerkit
Operaatio-nimitystä (engl. operation) käytetään esimerkiksi matemaattisille operaatioille. Yleisesti ottaen puhutaan operaatiosta, kun koodirivillä esiintyy operaattori ja operandeja. Esimerkiksi 5 + 5 on operaatio.
Operaattori (engl. operator) on matematiikassa ja ohjelmoinnissa nimitys symboleille, jotka kuvaavat jotain operaatiota. Operaattorilla on aina vähintään yksi operandi, mutta useimmilla kaksi. Esimerkiksi +-merkki on yhteenlaskuoperaattori.
Operandi (engl. operand) on hieno matematiikassa ja ohjelmoinnissa käytössä oleva nimitys arvoille joita käytetään operaatiossa. Esimerkiksi 5 + 8 on yhteenlaskuoperaatio, jonka operandit ovat 5 ja 8. Operandien voidaan siis sanoa olevan operaatioiden kohteita.
Paikallinen muuttuja (eng. local variable) on muuttuja, joka on määritelty vain yhdessä kontekstissa, tyypillisesti - ja erityisesti tällä kurssilla - funktion sisällä (ml. funktion parametrit). Paikalliseen muuttujaan ei voi koskea ulkopuolelta, minkä lisäksi se lakkaa olemasta kun ohjelman suoritus poistuu sen kontekstista - eli yleensä kun funktion suoritus päättyy.
  1. Kuvaus
  2. Lisämuotoilu
Paikanpidin (engl. placeholder) on yleisesti tilapäinen merkintä, joka on tarkoitus korvata toisella. Tällä kurssilla sitä käytetään lähinnä merkkijonojen muotoilun yhteydessä. Paikanpidin merkkijonon sisällä merkitään aaltosulkeilla (f"Hei {nimi}"). Merkkijonojen paikanpitimissä voi olla lisämäärityksiä kuten näytettävien desimaalien lukumäärä (f"Aaseilla on keskimäärin {keskiarvo:.2f} jalkaa"). Paikanpitimien tilalle sijoitetaan sisällä olevan muuttujan tai lausekkeen arvo.
Pakeneminen (engl. escape) tarkoittaa ohjelmoinnissa sitä, että jokin merkki tulkitaan eri tavalla kuin normaalisti. Esimerkiksi "n" on vain n-kirjain, mutta "\n" on rivinvaihto – tässä siis \-merkki (kenoviiva, engl. backslash) aiheuttaa sen, että n-merkin normaali merkitys paetaan ja korvataan toisella merkityksellä; kenoviiva toimii siis koodinvaihtomerkkinä (engl. escape character). Yksi tyypillinen käyttö on sisällyttää "-merkki merkkijonoon, joka on rajattu "-merkeillä: "aasin korvien väli on 14\""
  1. Kuvaus
  2. Esimerkit
Palauttaminen (engl. return) tapahtuu aina kun funktion suoritus päättyy. Tyypillisesti funktion palauttama(t) arvo(t) määritellään funktion sisällä return-lauseella. Funktiota kutsuvassa koodissa paluuarvo näkyy funktiokutsun paikalla, jolloin se voidaan esimerkiksi tallentaa muuttujaan tai laittaa eteenpäin toiselle funktiolle.
Paluuarvo (engl. return value) on nimitys arvolle tai arvoille, jotka funktio palauttaa, kun sen suoritus päättyy - eli siis funktion tulos. Pythonissa funktiolla voi olla useita paluuarvoja. Koodia lukiessa paluuarvoa voi käsitellä päässään siten, että funktiokutsun paikalle sijoitetaan funktion paluuarvo sen jälkeen kun funktio on suoritettu. Paluuarvo löytyy funktion sisältä return-lauseen yhteydestä. return True -rivillä on yksi paluuarvo – totuusarvo True.
Parametri (engl. parameter) on funktion määrittelyssä nimetty muuttuja. Parametreihin sijoitetaan funktion saamien argumenttien arvot silloin, kun funktiota kutsutaan. Parametri on siis nimitys jota käytetään, kun puhutaan arvojen siirtymisestä funktion näkökulmasta. def kysy_syote(kysymys, virheviesti): -rivillä siis kysymys ja virheviesti ovat parametreja. Parametrille voidaan määrittää oletusarvo jonka se saa, jos sitä vastaavaa argumenttia ei anneta kutsuttaeassa – tämä tekee kyseisestä argumentista valinnaisen.
Parametrisaatio tarkoittaa jonkin prosessin käyttötarkoitusten laajentamista siten, että osa sen kiinteistä arvoista muutetaan muuttujiksi jolloin sama prosessi voidaan suorittaa eri arvoilla ja saada eri tulos. Esim. matemaattiset yhtälöt ovat eräänlaista parametrisaatiota: kaikki yhtälön kuvaavat pisteet tuotetaan samalla kaavalla vaihtamalla muuttujan (esim. x) arvoa. Ohjelmoinnissa parametrisaatio on hyvin konkreettista: tyypillisesti prosessi irrotetaan omaan funktioonsa jonka parametrit määrittävät mitkä arvot eivät ole kiinnitettyjä jolloin funktio toimii eri tavalla eri parametreilla, antaen esim. eri tuloksen.
  1. Kuvaus
  2. Esimerkit
Poikkeus (engl. exception) on ohjelmointikielessä määritelty virhetilanne. Poikkeuksella on tyyppi (esimerkiksi TypeError), jota voi käyttää poikkeuksen käsittelyssä ohjelman sisällä sekä myös apuna virhetilanteen ratkaisussa. Tyypillisesti poikkeukseen liitetään myös viesti, joka kertoo mistä ongelmassa on kyse. Pythonissa poikkeuksia käsitellään try-except-rakenteilla.
  1. Kuvaus
  2. try-except-else-finally
Poikkeusten käsittely (engl. exception handling) on ohjelmointikieleen sisäänrakennettu keino ohjelmoijalle reagoida poikkeuksiin. Pythonissa poikkeusten käsittely onnistuu try-except-rakenteella, jossa sekä try: että except: aloittavat omat lohkonsa; try-lohkon alle kirjoitetaan se koodi, joka mahdollisesti aiheuttaa jonkun tietyn poikkeuksen ja except-lohkon alle taas se koodi, joka suoritetaan siinä tapauksessa, että kyseinen poikkeus tapahtuu. Joissain muissa ohjelmointikielissä except-avainsanan sijaan käytetään avainsanaa catch, minkä takia yleisesti puhutaan poikkeusten kiinni ottamisesta.
  1. Kuvaus
  2. Esimerkit
Polku (engl. path) on tiedoston tai kansion sijainti kiintolevyllä. Polku voi olla absoluuttinen tai relatiivinen. Absoluuttinen polku sisältää kaikki kansiot aina juureen asti (esim. Windowsissa asemakirjain kuten C:), kun taas relatiivinen sisältää kansiot aktiiviseen kansioon asti (ts. siihen kansioon mistä ohjelma käynnistettiin). Polku esitetään ohjelmointikielissä yleensä merkkijonona, ja polun osat erotetaan kauttaviivalla /. Useimmiten polkuja muodostaessa kannattaa käyttää os.path-moduulin join-funktiota.
  1. Kuvaus
  2. Esimerkit
Interaktiivinen Python-tulkki (engl. interactive Python interpreter) tai Python-konsoli (engl. Python console) on ohjelma, johon voi kirjoittaa Python-koodirivejä. Nimitys ”interaktiivinen” tulee siitä, että koodirivi suoritetaan välittömästi sen syöttämisen jälkeen, ja ohjelma näyttää käyttäjälle koodirivin tuottaman paluuarvon (esimerkiksi matemaattisen operaation tuloksen). Kurssilla suositellaan IPython-tulkkia, joka käynnistetään asennuksen jälkeen komennolla ipython.
Python-tulkki (engl. Python interpreter) on ohjelma, joka muuttaa Python-koodin tietokoneelle annettaviksi ohjeiksi. Se vastaa niin kooditiedostojen kuin myös interaktiiviseen Python-tulkkiin kirjoitettujen komentojen suorittamisesta. Tällä kurssilla sanalla tulkki viitataan kuitenkin useimmiten nimenomaan interaktiiviseen Python-tulkkiin.
Pythonissa pääohjelma (engl. main program) on se osa koodia, joka suoritetaan, kun ohjelma käynnistetään. Nyrkkisääntönä pääohjelma sisältää kaikki lauseet sekä ohjausrakenteet jotka ovat kiinni koodin vasemmassa laidassa. Pääohjelma sijaitsee tyypillisesti koodin lopussa, ja useimmiten if __name__ == "__main__":-lauseen alla. Älä kuitenkaan käytä tätä lausetta alkupään harjoitustehtävissä, koska tarkistin ei pysty tällöin suorittamaan koodisi pääohjelmaa.
  1. Kuvaus
  2. Esimerkit
Rajapinta (engl. interface) viittaa yleisesti kahden eri asian välimaastoon, ja ohjelmoinnissa sillä tarkoitetaan erityisesti tapaa, jolla ohjelman eri osat voivat liittyä toisiinsa. Esimerkiksi funktion rajapinnasta puhuttaessa tarkoitetaan sitä muotoa, jossa funktio vastaanottaa tietoa ja suoriutumisen jälkeen antaa käsiteltyä tietoa tai jonkun lopputuloksen ulos. Kirjastoilla on yleensä olemassa jonkinlainen niin kutsuttu API, eli Application Programming Interface, joka kertoo sen, kuinka kirjaston toiminnallisuuksia käytetään. Ihmiset taas ovat ohjelmiin kytköksissä käyttöliittymän (engl. User Interface, lyh. UI) kautta, joka sekin on tietynlainen rajapinta.
Ratkaisumalli on ohjelmoijan muodostama abstrakti ajatus siitä miten ohjelmointiongelman ratkaisu etenee. Ratkaisumalli ei ole vielä koodia, mutta sen tulisi olla yksiselitteinen sekä selkeisiin välivaiheisiin jakaantuva, jotta sen pohjalta voidaan kirjoittaa ohjelma. Ratkaisumallia voi hahmotella päänsisäisesti, käyttämällä avuksi paperia sekä kokeilemalla asioita Python-tulkissa.
  1. Kuvaus
  2. Esimerkit
Rekursio (engl. recursion) on yleinen ohjelmointitermi, joka viittaa siihen, kun funktio kutsuu itseään. Rekursio on siis funktiopohjainen tapa luoda toistorakenne, jossa funktio välittää itselleen uusia argumentteja ja käsittelee omia paluuarvojaan. Rekursio on kätevä esimerkiksi puumaisia rakenteita käsitellessä – käsitellään yksi ”oksa” jollain tavalla, ja sitten rekursion avulla käsitellään tästä oksasta lähtevät oksat ja niin edelleen. Pythonissa rekursiota käytetään aika vähän. Osasyynä on sisäänrakennettu rekursiorajoitus, joka asettaa katon sille, kuinka monta kertaa funktio saa kutsua itseään.
Relatiivinen polku (relative path) on käyttöjärjestelmäkäsite, joka kertoo hakemiston tai tiedoston osoitteen suhteessa aktiiviseen hakemistoon (eli siihen missä komento suoritetaan). Relatiivinen polku ei välitä siitä millainen hakemistoviidakko on levyaseman juuren ja aktiivisen hakemiston välissä. Tästä johtuen relatiivista polkua käytetään yleensä ohjelman omiin alikansioihin viittaamiseen. Tällöin ohjelma alikansioineen voidaan siirtää toiseen paikkaan ilman, että polkuja tarvii muuttaa.
Rivinvaihtomerkki (engl. newline, line break, end of line; lyh. EOL) eli "\n" on merkki, joka tulostettaessa tai tiedostoon kirjoitettaessa saa aikaan rivinvaihdon. Jos merkkijonoa tarkastellaan ilman printtausta esim. konsolissa, rivinvaihdot näkyvät "\n"-merkkeinä.
  1. Kuvaus
  2. Määrittely
  3. Arvojen haku
  4. Sanakirjan muuttaminen
Sanakirja (engl. dictionary) on tietorakenne, jossa arvoille annetaan avaimet (yleensä merkkijono). Sanakirjan merkittävin etu on se, että selkeästi nimetyt avaimet tekevät tietorakennetta käsittelevästä koodista huomattavasti selkeämpää luettavaa. Python 3.7:sta lähtien sanakirjan avaimet ja arvot ovat siinä järjestyksessä missä ne on lisätty.
Sapluuna (engl. template) on muotti esimerkiksi tekstille, joka käyttäjälle halutaan näyttää, mutta joka ei semmoisenaan ole vielä valmis. Sapluunasta siis puuttuu tietoa, joka on tarkoitus saada sapluunan paikanpitimien tilalle.
Kurssilla yleisin sapluuna on merkkijono, jossa on paikanpitimiä format-metodia varten.
Sekvenssi (engl. sequence) on mikä tahansa arvo Pythonissa, jossa on tavaraa peräkkäin – esimerkiksi merkkijono, lista ja monikko kuuluvat näihin.
Matematiikasta tuttu sidontajärjestys (engl. precedence) määrittää sen, missä järjestyksessä lausekkeen operaatiot suoritetaan.
lopputulos = 10 + 2 * (2 + 3)
Yllä olevan koodin lopputulos on 20, sillä ensin lasketaan yhteen luvut 2 ja 3, joiden summa kerrotaan kahdella, ja johon lopuksi lasketaan vielä yhteen luku 10. Esimerkissä korkein presedenssi on siis sulkeilla, toisiksi korkein kertolaskulla ja matalin yhteenlaskulla.
Sijoittaminen (engl. assignment) liittyy muuttujiin ja arvoihin. Tyypillinen ilmaisu on ”muuttujaan sijoittaminen”, joka yksinkertaistettuna tarkoittaa sitä, että tietty arvo annetaan muuttujalle (x = 5). Tarkennettuna muuttujaan sijoittaminen kuitenkin tarkoittaa Pythonissa sitä, että muuttujan ja arvon välille luodaan viittaus – muuttuja tietää mistä arvo löytyy.
Samaa tarkoittavia ilmaisuja ovat mm. muuttujaan tallentaminen, arvon ottaminen ylös muuttujaan, arvoon viittaminen muuttujalla, arvon tunkeminen muuttujaan... jne.
Sijoitusoperaattoria (engl. assignment operator) eli =-merkkiä käytetään muuttujaan sijoituksessa. Operaattoria käytettäessä kohteena olevan muuttujan tulee aina olla sen vasemmalla puolen ja sijoitettavan arvon (tai lausekkeen, joka tuottaa sijoitettavan arvon) sen oikealla puolen.
Silmukkamuuttuja (engl. loop variable) on for-silmukan määrittelrivillä esitelty muuttuja, joka saa yksitellen kaikki läpikäytävän sekvenssin (esim. lista) arvot. Sen arvo siis vaihtuu jokaisella silmukan kierroksella. Yksinkertainen esimerkki materiaalista: for elain in elukoita:, jossa siis elain on silmukkamuuttuja. Mikäli läpikäytävä sekvenssi sisältää monikoita (tai listoja), silmukkamuuttujia voi olla myös useita: for opiskelija, arvosana in arvostelu:. Silmukkamuuttujat eivät ole erillisessä nimiavaruudessa, joten niiden tulee erota muista funktion/pääohjelman muuttujista.
Sisennetyn (engl. indented) koodirivin edessä on tyhjää eli välilyöntejä tai sarkainmerkkejä. Sisennyksen tehtävä on parantaa koodin luettavuutta yleisesti. Pythonissa sisennys myös erottaa koodilohkot toisistaan - kaikki samalla sisennystasolla olevat rivit ovat samaa lohkoa. Tällä kurssilla käytetään välilyöntejä, ja yksi sisennys on 4 välilyöntiä. Kaikki järkevät tekstieditorit saa syöttämään sarkainmerkin sijaan halutun määrän välejä.
Sisäänrakennetut funktiot (engl. builtin functions) ovat funktioita, jotka tulevat Pythonin mukana, ja niitä käyttääkseen ei tarvitse erikseen ottaa käyttöön mitään moduulia/kirjastoa.
Suorittaminen (engl. execution) tai ajaminen (engl. running) tarkoittaa ohjelman tai koodinpätkän koneistettua läpi käymistä, jolloin ohjelmassa tai koodissa määritellyt asiat tapahtuvat. Python-tulkki suorittaa sille annettua koodia lause kerrallaan – tällöin ohjelman sanotaan olevan käynnissä. Kun enempää suoritettavaa koodia ei ole, törmätään käsittelemättömään virheeseen tai koodissa erikseen niin määrätään, ohjelman suorittaminen päättyy.
Suoritusjärjestys (eng. presedence) määrittää missä järjestyksessä koodirivillä olevat lauseet suoritetaan. Eri tyyppisillä operaatioilla on eri prioriteetti suoritusjärjestyksesä. Ne löytyvät alla olevasta linkistä. Samantasoiset operaatiot suoritetaan vasemmalta oikealle. Kuten matematiikassa, suoritusjärjestykseen voi vaikuttaa suluilla.
Syntaksi (engl. syntax) on koodin kielioppi. Esimerkiksi Pythonin syntaksi määrittää, millainen teksti on tulkittavissa Python-koodiksi. Jos teksti ei noudata koodin syntaksia, sitä ei voida suorittaa. Syntaksi antaa myös koodaajalle tietoa siitä, missä muodossa halutunlainen ohje tulee antaa.
Syntaksivirhe (engl. syntax error) on poikkeus, joka syntyy, kun Python-tulkki tutkii kooditiedostoa ennen sen suorittamista ja havaitsee siellä rikkinäistä – eli jollain tapaa väärin kirjoitettua – koodia. Syntaksivirhe estää koodin suorittamisen.
Yksi hyvin yleinen syntaksivirhe on sulkujen auki jääminen. Tällöin syntaksivirheilmoitus näyttää poikkeuksen tapahtuneen vasta virheellistä riviä seuraavalla rivillä! Muista siis mystisen syntaksivirheviestin äärellä katsoa myös edeltäviä rivejä.
  1. Kuvaus
  2. Esimerkit
Syöte (engl. input) on tämän kurssin puitteissa käyttäjältä pyydetty tekstimuotoinen komento tai vastaus kysymykseen. Syöte kysytään input-funktiolla, ja se on aina merkkijono. Aina, kun ohjelma kysyy syötettä, sen suoritus pysähtyy, kunnes käyttäjä on antanut syötteen.
Takaisinkutsu (engl. callback) on yleinen ohjelmoinnissa käytetty menetelmä, jossa funktio ottaa parametrin kautta vastaan funktion kutsuttavakseen heti (synkroniset takaisinkutsut) tai joskus tulevaisuudessa (asynkroniset takaisinkutsut). Nimensä menetelmä on saanut soittopyynnöstä: kutsuttavaa funktiota, jolle jokin funktio välitetään argumenttina, ”pyydetään” kutsumaan tätä annettua funktiota. Pythonissa listojen sort()-metodin key-parametri on esimerkki callback-funktioiden käytöstä. Usein käyttöliittymiä toteutettaessa käyttöliittymäelementteihin kytketään callback-funktioita.
Tallennusformaatti on tiedoston "syntaksi", joka siis kertoo miten data on tiedostoon tallennettu. Tallennusformaatti asettaa rajat sille millaista dataa tiedostossa voidaan esittää. Sen perusajatus on se, että koodissa olevat tietorakenteet voidaan tallentaa tiedostoon jossain muodossa, ja myöhemmin ladata sieltä uudelleen. Tallennusformaatti voi seurata jotain alan standardia (esim. JSON), mutta lopullisesti on ohjelman tekijän vastuulla päättää mitkä tiedot ovat ohjelman kannalta relevantteja ja miten ne on paras esittää.
Tapahtuma (engl. event) on ohjelmointikäsite, jota käytetään yleisesti interaktiivisten sovellusten, jotka pyörivät reaaliajassa, yhteydessä. Näissä sovelluksissa on yleensä pääsilmukka, joka tarkkailee tapahtumia, joita voivat olla esimerkiksi: käyttäjä klikkaa hiirellä, käyttäjä painaa näppäimistön nappia, tietty aika on kulunut jne. Tapahtumiin voidaan kiinnittää käsittelijäfunktioita, jolloin funktiota kutsutaan aina kun tapahtuma havaitaan. Tällä tavalla helpotetaan merkittävästi interaktiivisten sovellusten ohjelmointia, koska itse sovellusta kirjoittaessa ei tarvitse huolehtia siitä miten ruudun tapahtumat tunnistetaan.
Periaatteessa tekstitiedosto (engl. text file) on mikä tahansa tiedosto, jonka sisältö voidaan lukea nätisti tekstieditorilla. Tämän kurssin kontekstissa kuitenkin tekstitiedosto on erityisesti sellainen tiedosto, jonka sisältöä käsitellään tekstinä Pythonissa. Eli siinä missä kooditiedostoja suoritetaan, tekstitiedostoja käytetään datan varastoimiseen ohjelman ajojen välillä.
Terminaali (engl. terminal), komentokehote (engl. prompt) ja komentorivi (engl. command line) ovat eri nimiä käyttöjärjestelmän tekstipohjaiselle käyttöikkunalle. Komentorivillä annetaan tekstikomentoja käyttöjärjestelmälle. Tällä kurssilla pääasiassa siirrytään cd- eli change directory -komennolla hakemistosta toiseen ja käytetään ipython-komentoa kooditiedostojen suorittamiseen sekä interaktiivisen tulkin avaamiseen.
  • Windowsissa komentoriville pääsee kirjoittamalla käynnistä-valikon hakuun cmd
  • Mac OS X -käyttöjärjestelmässä komentorivin saa auki kirjoittamalla Finderiin pääte (suomen kielisissä versioissa) tai terminal (englannin kielisissä versioissa)
  • Linux-työpöytäympäristöistä voit painaa Ctrl + Alt + T työpöydällä tai kirjoittaa hakuun {{terminal}}}
Testaamalla eli kokeilemalla (engl. test) selvitetään, toimivatko hartaasti näppäillyt koodirivit halutulla tavalla. Testejä suorittamalla siis etsitään koodista mahdollisia ohjelmointivirheitä. Ohjelmien testaaminen on jopa niin olennaista, että joidenkin alan työntekijöiden tehtävänä on ainoastaan automatisoitujen testien ohjelmointi. Lovelace-järjestelmän tarkistimet testaavat järjestelmään lähetetyt koodit.
Tiedostokahva (engl. file handle) on erityinen objekti, jota Pythonissa käytetään avattuun tiedostoon viittaamiseen. Huomattavaa on, että kahva ei ole sama asia kuin tiedoston sisältö, mutta sen kautta voidaan lukea tiedoston sisältö tai kirjoittaa tiedostoon. Tiedostokahva saadaan käyttöön open-funktiolla, jolle määritetään avattavan tiedoston sijainti sekä avausmoodi, jossa se avataan, esim: with open("aasi.txt", "r") as tiedosto: avaa aasi.txt-tiedoston with-lauseessa (jossa tiedostot tulee yleensä avata) siten, että muuttujasta nimeltä tiedosto löytyy tiedostokahva.
Tiedostonimi (engl. filename) on tiedoston koko nimi, joka sisältää varsinaisen tiedostolle annetun nimen sekä tiedostopäätteen. Esimerkiksi aasisvengaa.py on kokonainen tiedoston nimi, jossa varsinainen annettu nimi on aasisvengaa ja pääte on .py.
Koodin sisällä tiedostojen nimet esitetään merkkijonoina.
Tiedostopääte (engl. filename extension) on se osa tiedoston nimestä, joka on viimeisen pisteen oikealle puolen. Tiedostopäätteet ovat yleisesti käytetty tapa tiedostojen sisällön tunnistamiseen, eli ne ovat keino ilmaista tiedoston tyyppiä. Esimerkiksi kuvatiedostoilla voi olla vaikkapa .png- tai .jpg-pääte, kun taas Python-kooditiedoston pääte on yleensä .py, kuten nimessä aasisvengaa.py.
Tietorakenne (engl. data structure) on yleisnimitys kokoelmille, jotka sisältävät useita arvoja. Tietorakenteen tarkoitus on siis säilöä useammasta kuin yhdestä arvosta koostuvaa tietoa jollain lukuisista eri tavoista, joille kullekin yleensä on olemassa tietorakenteen helpon hyödyntämisen mahdollistavat ohjelmointikeinot, kuten arvojen lisääminen, poistaminen ja muokkaaminen tietorakenteesta. Tietorakenne on siis ohjelman sisäinen tapa käsitellä dataa siten, että varsinaiset yksityiskohdat on piilotettu ohjelmoijalta, joka käyttää tietorakenteita koodissaan.
Omissa ohjelmissa käytettävät tietorakenteet tulisikin valita siten, että niitä on helppo käsitellä koodissa, ja että ne palvelevat hyvin ohjelman tarkoitusta. Pythonissa yleisimmät tietorakenteet ovat lista, monikko ja sanakirja. Myös set – eli joukko-opillinen joukko, joka ei sisällä duplikaattiarvoja – on käytännöllinen tietorakenne. Sisäänrakennettujen lisäksi lukuisia käytänöllisiä tietorakenteita löytyy collections-moduulista.
Myöhemmillä kursseilla tutuksi tulevat myös muun muassa tärkeät tietorakenteet puu (engl. tree) ja graafi (engl. graph).
Tila (engl. state) viittaa sananmukaisesti ohjelman tilanteeseen. Käytännössä ohjelman tila kattaa kaikki sen tila-avaruuteen (engl. state space) kuuluvat asiat, kuten muuttujien arvot, tiedostoissa olevan datan ja sen, mitä kohtaa koodista sillä hetkellä ollaan suorittamassa. Taattu keino saada aikaiseksi korjauskelvotonta spagettikoodia on käyttää niin kutsuttua globaalia tilaa (engl. global state) – rikos, johon syyllistyvät epäpuhtaat globaaleja muuttujia hyödyntävät funktiot.
Myöhemmillä, ohjelmoinnin käsitteitä formaalimmin tutkivilla kursseilla tutuksi tulevat muun muassa tilakoneet (engl. state machine) sekä tilattomat (engl. stateless) että tilalliset (engl. stateful) ohjelmat.
Toistorakenne tai silmukka (engl. loop) on ohjausrakenne, jonka alaisuuteen kirjoitettua koodia toistetaan joko tietty lukumäärä toistoja tai kunnes jokin ehto lakkaa toteutumasta. Toistorakenteiden avulla ohjelmat pystyvät jouhevasti palaamaan aiempaan kohtaan suoritusta ja niillä voidaan myös helposti käsitellä suuria määriä arvoja. Toistorakenteita ovat Pythonissa for- ja while-silmukat.
Tosi (engl. true) on toinen kahdesta mahdollisesta totuusarvosta ja toisen, eli epätoden, vastakohta. Sitä voidaan pitää lopputuloksena loogisissa ja vertailuoperaatorioissa, jotka pitävät paikkansa. Esimerkiksi vertailuoperaatio 5 > 4 pitää paikkansa, joten kyseinen operaatio evaluoituu todeksi. Pythonissa totta merkitään avainsanalla True.
Totuusarvo (engl. boolean) on yleensä ohjelmointikielien yksinkertaisin tietotyyppi, jolla on vain kaksi arvoa: tosi (Pythonissa True) ja epätosi (Pythonissa False). Vertailuoperaattorit tuottavat totuusarvoja, ja niitä käytetään yleisimmin ehtolauseiden ja while-silmukoiden yhteydessä. Pythonissa kaikki arvot vastaavat jompaa kumpaa totuusarvoa. Yleisesti ns. tyhjät arvot (0, "", None jne.) ovat sama kuin False, ja loput sama kuin True.
  1. Kuvaus
  2. Esimerkit
Traceback – taaksepäin jäljittäminen – viittaa yleiseen tapaan tutkia virhetilanteen syntymistä sen juurilta alkaen. Python-tulkki tulostaa virhetilanteessa virheviestin, johon olennaisesti kuuluu traceback. Traceback esitetään purkamalla ohjelman funktiokutsuista syntynyt pino, jonka viimeisimmässä osassa varsinainen virhe tapahtui. Tästä syystä tracebackeja kutsutaan myös nimellä stacktrace, eli pinon jäljittäminen. Jos esimerkiksi pääohjelmassa kutsutaan funktiota f, josta käsin kutsutaan funktiota g, jossa virhe tapahtuu, funktiokutsujen pino on muotoa pääohjelmafg.
  1. Kuvaus
  2. Esimerkit
Tulostaminen (engl. print) onkin ohjelmoinnissa jotain muuta – joskaan ei lopulta periaatteiltaan kovin erilaista – kuin paperin ja musteen yhdistämistä halutunlaisiksi sivuiksi. Tietokoneohjelmien yhteydessä tulostamisella tarkoitetaan tekstin tuottamista esiin näytölle, erityisesti terminaaliin. Pythonissa tätä varten on oma funktio, print(...), joka tulostaa sille annetun argumentin terminaaliin.
  1. Kuvaus
  2. Esimerkit
Tynkäfunktio (engl. stub function) on funktio, jolle on kirjoitettu oikeanlainen määrittelyrivi parametreineen, mutta ei oikeaa sisältöä. Niitä yleensä kirjoitetaan koodiin ohjelman rakennetta suunniteltaessa sekä mahdollistamaan funktioiden kutsuminen muualle ohjelmassa siten, että sitä voidaan testata ennen kuin funktioiden toteutus on valmis. Tynkäfunktion sisältönä on usein pelkkä pass, joku informatiivinen tulostus tai jonkin oletusarvon palautus. Isommissa Python-ohjelmissa tynkäfunktioissa on tapana aiheuttaa NotImplementedError-poikkeus, jolloin reitti toteuttamattoman funktion kutsuun on helppo löytää tracebackistä.
Tyylisäännöt ovat kokoelma suosituksia, joiden mukaan koodia tulisi kirjoittaa. Kullakin kielellä on yleensä omansa. Tyylisääntöjen rikkominen ei varsinaisesti riko ohjelmaa, mutta tyylisääntöjen mukainen koodi on miellyttävämpää lukea ja usein tästä johtuen myös helpompi korjata. Tällä kurssilla seurataan Pythonin virallista tyylistandardia erityisesti tekstikenttätehtävissä. Myös tiedostotehtävissä on koodin laadun tarkistus, jossa käytetään PyLint-ohjelmaa.
  1. Kuvaus
  2. Esimerkit
Tyyppi (engl. type) on arvon ominaisuus – jokainen arvo edustaa aina jotain tiettyä tyyppiä. Tyypin tarkoitus on siis kertoa, minkälaisesta arvosta on kyse. Käytännössä tästä seuraa myös se, mitä operaatioita arvoilla voi tehdä, ja mitä metodeja niiltä löytyy. Funktiot on myös miltei aina toteutettu siten, että niille syötettävien argumenttien täytyy olla tietyntyyppisiä, jotta funktio voisi toimia. Tyypit ovat yksi ohjelmoinnin keskeisimmistä käsitteistä.
Pythonissa arvojen sopiminen koodista löytyviin operaatioihin tarkistetaan tilannekohtaisesti näiden arvon ominaisuuksien perusteella – ei siis suoraan itse tyyppiä tarkastamalla. Esimerkiksi useimmissa tapauksissa kokonaisluku ja liukuluku kelpaavat molemmat, mutta on myös tapauksia, joissa näin ei ole (esimerkiksi merkkijonoa ei voi kertoa liukuluvulla).
Tällä kurssilla tyypillisiä tyyppejä ovat kokonaisluku (int), liukuluku (float), merkkijono (str), lista (list), totuusarvo (bool) ja monikko (tuple). Myös funktioilla on oma tyyppinsä!
  1. Kuvaus
  2. Esimerkit
Tyyppimuunnos (engl. type casting, type conversion, type coercion) tarkoittaa sananmukaisesti jonkin koodissa esiintyvän muuttujan tai literaaliarvon tyypin muuntamista toiseksi. Pythonissa tähän törmää usein, kun käyttäjältä on saatu merkkijonona luku, jota halutaan käsitellä esimerkiksi kokonais- tai liukulukuna. Käytännössä tämä onnistuu esimerkiksi lauseilla int("123") tai float("3.14"). Joissain tilanteissa Python-tulkki suorittaa tyyppimuunnoksen automaattisesti, kuten laskettaessa yhteen kokonais- ja liukulukuja.
  1. Kuvaus
  2. Esimerkit
Vakio (engl. constant) on nimetty literaaliarvo. Niitä käytetään erityisesti silloin kun sama literaaliarvo esiintyy koodissa useasti. Yleisesti ottaen nimetty vakio on käytännöllisempi kuin koodissa oleva literaaliarvo, koska sen nimestä voi päätellä mitä se tekee. Samaten jos arvoa tarvitsee muuttaa, vakioita käyttäessä tarvitsee muuttaa vain kohtaa jossa se määritellään. Pythonissa ei ole erillistä tapaa luoda vakioita vaan ne ovat periaatteessa ihan vain muuttujia. Vakioiden nimet kirjoitetaan isolla. Esimerkiksi VASTAUS = 42.
Funktiota kutsuttaessa argumentti on valinnainen (engl. optional argument), jos funktiossa sitä vastaavalle parametrille on määritetty oletusarvo. Tällöin kyseistä argumenttia ei ole pakollista antaa funktiokutsussa. Jos valinnaisia argumentteja on useita, ne annetaan tyypillisesti avainsana-argumentteina.
Vertailuarvoa käytetään esim. listojen järjestämisessä. Vertailuarvo on listan alkiosta johdettu arvo, jota käytetään järjestämisperusteena. Esimerkiksi jos lista sisältää listoja, vertailuarvo voi olla jostain tietystä indeksistä otettu alkio. Se voi olla myös monimutkaisempi johdannainen, kuten listan alkioiden summa tai keskiarvo.
Vertailuoperaattoreita (engl. comparison operators) käytetään, kun verrataan arvoja toisiinsa. Ne ovat matematiikasta tuttuja ja niillä voidaan verrata suuruksia. Vertailuoperaattorit palauttavat totuusarvon True tai False riippuen vertailun lopputuloksesta. Vertailuoperaattoreita ovat <, <=, >, >=, == ja !=.
Ohjelmoinnin asiayhteydessä viittaaminen (engl. reference) tarkoittaa tapaa, jolla muuttuja liittyy arvoonsa. Viittauksen kohde on tietokoneen muisti, ja muuttuja itsessään – konepellin alla – sisältää osoitteen, mistä kohdasta tietokoneen muistia siihen liitetty arvo löytyy.
  1. Kuvaus
  2. Esimerkit
Virheviesti (engl. error message) on Python-tulkin tapa ilmoittaa koodissa tapahtuneesta poikkeuksesta. Virheviestiin kuuluu tieto siitä missä kohdassa koodin suoritusta se tapahtui, mikä rivi kooditiedostossa aiheutti poikkeuksen, poikkeuksen tyyppi (esimerkiksi SyntaxError) sekä lyhyt sanallinen kuvaus. Virheviestit ovat ohjelmoijan paras ystävä, ja niiden lukeminen on erittäin oleellinen ohjelmointitaito. Niitä ei siis ole syytä säikähtää, sillä ne auttavat selvittämään, mikä ohjelman koodissa on pielessä!
  1. Kuvaus
  2. Esimerkit
Avainsana break on erityinen komento, jota käytetään toistorakenteissa. Se päättää silmukan suorituksen välittömästi, ja koodin suoritus jatkuu ensimmäiseltä silmukan jälkeiseltä riviltä. Jos silmukassa oli else-osa, siihen ei mennä.
  1. Kuvaus
  2. Esimerkit
continue on toinen toistorakenteisiin liittyvä avainsana (toisen ollessa break). Toisin kuin break, joka lopettaa koko silmukan suorituksen, continue keskeyttää ainoastaan meneillään olevan kierroksen suorituksen – suoritus jatkuu siis seuraavasta kierroksesta. Huomaa, että tätä avainsanaa tarvitaan vain tilanteissa, joissa halutaan jättää osa kierroksesta suorittamatta, eli silmukan kierroksen loppuun ei ole tarpeen laittaa continue-avainsanaa.
  1. Kuvaus
  2. Esimerkit
enumerate on Pythonissa sisäänrakennettu funktion kaltainen erityisobjekti, joka tuottaa generaattoriobjektin. Sitä käytetään pääasiassa for-silmukoissa silloin, kun on tarpeen saada läpi käytävän listan alkioiden indeksit käyttöön silmukan sisällä. enumerate-objekti tuottaa monikkoja, joissa ensimmäisenä on alkion indeksi ja toisena itse alkio. Käyttöesimerkki: for i, hahmo in enumerate(muumilaakso):.
f(ormat)-merkkijono on erityinen merkkijono, jota käytetään, kun halutaan tuottaa tekstiä jonka sisään on sijoitettu muuttujien tai yksinkertaisten lausekkeiden arvoja. Tällainen merkkijono merkitään laittamalla sen eteen pieni f-kirjain. Merkkijonon sisällä voidaan käyttää aaltosulkeilla merkittyjä paikanpitimiä, joiden sisälle voidaan kirjoittaa muuttujien nimiä tai lausekkeita.
Esimerkki: f"Aasin korvien väli on {mittaus:.2f} tuumaa" (olettaen että mittaus-niminen muuttuja on aikaisemmin määritelty).
  1. Kuvaus
  2. Esimerkit
Pythonissa for on toinen silmukkatyyppi. Sen käyttötarkoitus on tietorakenteiden läpikäyminen – iterointi. Sitä käytetään erityisesti listojen kanssa. Yleisesti ottaen for-silmukkaa käytetään silloin, kun pystytään ennalta määrittämään montako kierrosta silmukkaa tulee pyörittää. Tietorakenteiden läpikäynnin lisäksi näihin lukeutuu tietyn toistomäärän tekeminen (esimerkiksi kymmenen toistoa). Silmukan määrittelyrivi on muotoa: for alkio in lista:, jossa alkion paikalle tulee silmukkamuuttujan nimi ja listan paikalla ilmoitetaan läpikäytävä tietorakenne.
  1. Kuvaus
  2. Esimerkit
Pythonissa moduuleja otetaan käyttöön import-lauseella. Normaalikäytössä (esim. import math) lause tuo ohjelmaan uuden nimiavaruuden, joka on sama kuin moduulin nimi. Tämän nimen kautta päästään käsiksi moduulin funktioihin. Nimistä voi myös tuoda ainoastaan osan from-import-lauseella: from math import ceil. Moduulille voidaan myös antaa eri nimi as-avainsanalla: import math as m.
  1. Kuvaus
  2. Esimerkit
Silmukoista while pohjautuu toistoon ehdon tarkastelun kautta - silmukan sisällä olevaa koodilohkoa suoritetaan niin kauan kuin silmukalle annettu ehto on tosi. Ehto määritetään samalla tavalla kuin ehtolauseissa, esim: while summa < 21. While-silmukat soveltuvat parhaiten sellaisiin tilanteisiin, joissa ei voida etukäteen selvittää montako toistoa tarvitaan - erityisesti syötteiden kysyminen käyttäjältä on tällainen tilanne.
  1. Kuvaus
  2. Esimerkit
Pythonissa with on hieman muista poikkeava avainsana, sillä se ei ole varsinaisesti ohjausrakenne tai uuden asian määrittely. Tällä kurssilla sitä käytetään pääasiassa tiedostojen avaamisessa, tyyliin with open("aasi.txt") as tiedosto:. Tiedoston luku- tai kirjoitusoperaatiot suoritetaan with-lauseen alla. Kun with-lohko päättyy, Python huolehtii automaattisesti with-lauseessa avattujen tiedostojen yms. sulkemisesta.