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. Purkaminen
    12. Python-konsoli
      työkalut
    13. Python-tulkki
      työkalut
    14. Pääohjelma
      konseptit
    15. 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ää

5. Materiaali: Käyttöliittymä ikkunassa

Tämä on valinnainen materiaali, joka on tarpeellinen lopputyön tekijöille. Tämän materiaalin sisältö ei kuulu kurssin tenttialueeseen, ja tentti olisikin hyvä olla suoritettuna ennen tähän materiaaliin sukeltamista.
Terminaalissa pyörivät tekstiohjelmat ovat hiukan liian 80-lukua. Nykyaikana voisi ehkä edes yrittää tehdä jotain mikä avautuu omaan ikkunaansa ja jota voi tökkiä hiirellä tai kosketusnäytöllä. Viimeistellään siis urakka siirtämällä kokoelmaohjelma terminaalista ikkunaan. Tässä opittavat asiat eivät varsinaisesti kuulu alkeisiin, mutta nykyaikana suuri osa ohjelmoinnista perustuu tässä läpikäytäviin käsitteisiin. Lisäksi nykyaikana työkalut grafiikan tekoon koodilla ovat sen verran päheitä, että pienellä pintaraapaisullakin saa paljon aikaan.
Ilman suunnitelmaa ei kannata tähänkään projektiin ryhtyä. Ei ole ehkä syytä lähteä tavoittelemaan kuuta taivaalta, joten tyydytään hienojen käyttökokemusten sijaan lähinnä siihen, että saadaan ohjelman nykyiset tekstimuotoiset valikkorakenteet muutettua graafisiksi siten, että päätoiminnot löytyvät painikkeina ohjelman pääkäyttöliittymästä ja alivalikot aukeavat tarpeen mukaan erillisiin ali-ikkunoihin. Kokoelman sisältö näkyy jonkinlaisessa taulukossa tai tekstilaatikossa pääikkunassa. Tarvitaan siis
kirjasto
, joka kykenee tarjoamaan nämä perustoiminnot.
Kannattaa myös esimerkkiä lukiessa pitää mielessä, että se on monimutkaisempi kuin lopputyön minimivaatimukset - siellä siis pääsee vähemmällä.
Osaamistavoitteet: Oppia hyvin minimaaliset perusteet siitä miten modernit käyttöliittymäkirjastot toimivat. Tähän kuuluu aivan erityisesti
käsittelijäfunktioiden
sielunelämän ymmärtäminen ja siihen miten niiden välillä tulisi jakaa informaatiota. Lisäksi opitaan miten yksi kurssin lopputöitä varten tehty graafinen käyttöliittymäkirjasto toimii. Toinen opitaan viimeisestä harjoitusesimerkistä.

Kirjastoesittely

Normaalisti tässä vaiheessa tehtäisiin hieman tutkimusta siitä mikä kirjasto sopii parhaiten tarkoitukseen. Tämä jätetään kuitenkin tällä kertaa tekemättä, koska alkeiskurssin tiedoilla ei oikeasti voi vielä kovin hyvin tällaista arvioida. Pythonin mukana tulee TKinter-kirjasto, joka on vanha kuin taivas, ja jonka tuottama jälki on rumaa kuin suolaisen Dota-pelaajan käytös kolmelta aamuyöllä, mutta se sattuu tekemään kaikki graafisen käyttöliittymän perusteet aika yksinkertaisella tavalla. Ei tosin niin yksinkertaisella, että niitäkään olisi syytä alkaa tässä tarkemmin purkaa. Sen sijaan käytämme tätä kurssia varten tehtyä palikkaa, joka yksinkertaistaa TKinterin toiminnoista osan muutamaan helposti käsitettävään
funktioon
. Koodi on myös dokumentoitu
dokumenttimerkkijonoilla
kohtalaisen yksityiskohtaisesti.
ikkunasto.py
"""
ikkunasto - yksinkertainen käyttöliittymäkirjasto

@author Mika Oja, Oulun yliopisto

Tämä kirjasto sisältää nipun funktioita, joilla opiskelijat voivat toteuttaa
yksinkertaisen käyttöliittymän, jossa hyödynnetään matplotlib-kirjastoa
kuvaajien piirtämiseen. Kirjasto sisältää paljon oletusratkaisuja, jotta
opiskelijoiden ei tarvitse opetella kokonaista käyttöliittymäkirjastoa, eikä
paneutua sellaisen yksityiskohtiin. Tästä syystä käyttöliittymien toteutuksessa
voi kuitenkin tulla rajoja vastaan.

Kirjasto on rakennettu Pythonin mukana tulevan TkInterin päälle. Lisätietoa
löytyy mm. täältä:

https://docs.python.org/3/library/tk.html

Erityisen huomattavaa on, että Tk hoitaa pääasiassa automaattiseti elementtien
sijoittelun (perustuen siihen missä kehyksissä ne ovat), mutta kuvaaja- ja
tekstilaatikoiden koko määritetään staattisesti - niiden ulottuvuudet siis
sanelevat aika pitkälti miltä käyttöliittymä näyttää. Jos siis haluat
siistimmän näköisen käyttöliittymän, kannattaa kokeilla säätää näiden kokoja.

Kirjaston pääohjelmasta löydät pienen esimerkkikoodin, josta saat jonkinlaisen
käsityksen siitä miten tätä kirjastoa käyttämällä luodaan käyttöliittymän
peruselementtejä.
"""

import tkinter as tk
from tkinter.ttk import Separator
from tkinter import messagebox, filedialog

VASEN = tk.LEFT
OIKEA = tk.RIGHT
YLA = tk.TOP
ALA = tk.BOTTOM

def luo_ikkuna(otsikko):
    """
    Luo ikkunan käyttöliittymää varten. Ikkuna toimii kaiken pohjana, joten
    tätä funktiota pitää kutsua ennen kuin muita voidaan käyttää.

    :param str otsikko: ikkunan otsikko
    :return: palauttaa luodun ikkunaobjektin
    """

    # käytetään globaalia muuttujaa jotta kaynnista- ja lopeta-funktiot
    # toimivat ilman parametreja
    global ikkuna
    ikkuna = tk.Tk()
    ikkuna.wm_title(otsikko)
    return ikkuna

def luo_kehys(isanta, puoli=VASEN):
    """
    Luo kehyksen, johon voidaan asetella muita elementtejä. Kehyksillä voidaan
    jakaa käyttöliittymä helpommin käsiteltäviin alueisiin. Niitä tarvitaan
    myös, jos halutaan asetella komponentteja muutenkin kuin yhden akselin
    suuntaisesti.

    Kehykset voivat sijaita itse ikkunassa, tai toisten kehysten sisällä.
    Funktion ensimmäinen parametri on siis joko ikkunaobjekti tai kehysobjekti.
    Toinen parametri vaikuttaa siihen, mihin kehys sijoitetaan. Elementit
    pakataan aina jotain seinää vasten - ne siis muodostavat pinon. Jos esim.
    pakataan kaksi kehystä ylälaitaa vasten, ensimmäisenä pakattu kehys on
    ylimpänä ja toisena pakattu kehys sen alla.

    :param widget isanta: kehys tai ikkuna, jonka sisälle kehys sijoitetaan
    :param str puoli: mitä isäntäelementin reunaa vasten kehys pakataan
    :return: palauttaa luodun kehysobjektin
    """

    kehys = tk.Frame(isanta)
    kehys.pack(side=puoli, anchor="n")
    return kehys

def luo_nappi(kehys, teksti, kasittelija):
    """
    Luo napin, jota käyttäjä voi painaa. Napit toimivat käsittelijäfunktioiden
    kautta. Koodissasi tulee siis olla määriteltynä funktio, jota kutsutaan
    aina kun käyttäjä painaa nappia. Tämä funktio ei saa lainkaan argumentteja.
    Funktio annetaan tälle funktiokutsulle kasittelija-argumenttina. Esim.

    def aasi_nappi_kasittelija():
        # jotain tapahtuu

    luo_nappi(kehys, "aasi", aasi_nappi_kasittelija)

    Napit pakataan aina kehyksensä ylälaitaa vasten, joten ne tulevat näkyviin
    käyttöliittymään alekkain. Jos haluat asetella napit jotenkin muuten, voit
    katsoa tämän funktion koodista mallia ja toteuttaa vastaavan
    toiminnallisuuden omassa koodissasi. Jos laajenna-argumentiksi annetaan
    True, nappi käyttää kaiken jäljellä olevan tyhjän tilan kehyksestään.

    :param widget kehys: kehys, jonka sisälle nappi sijoitetaan
    :param str teksti: napissa näkyvä teksti
    :param function kasittelija: funktio, jota kutsutaan kun nappia painetaan
    :return: palauttaa luodun nappiobjektin
    """

    nappi = tk.Button(kehys, text=teksti, command=kasittelija)
    nappi.pack(side=tk.TOP, fill=tk.BOTH)
    return nappi

def luo_tekstilaatikko(kehys, leveys=80, korkeus=20):
    """
    Luo tekstilaatikon, johon voidaan kirjoittaa viestejä samaan tapaan kuin
    printillä komentoriviohjelmissa. Oletuksena tekstilaatikko täyttää kaiken
    vapaana olevan tilan kehyksestään. Tarkalleen ottaen luo kehyksen, jossa
    on sekä tekstilaatikko että siihen liitetty pystysuuntainen vierityspalkki.
    Kehystä ja vierityspalkkia ei kuitenkaan palauteta, ainoastaan itse
    laatikko.

    :param widget kehys: kehys, jonka sisälle tekstilaatikko sijoitetaan
    :param int leveys: laatikon leveys merkkeinä
    :param int korkeus: laatikon korkeus riveinä
    :return: tekstilaatikko-objekti
    """

    laatikkokehys = luo_kehys(kehys, tk.TOP)
    vieritin = tk.Scrollbar(laatikkokehys)
    laatikko = tk.Text(laatikkokehys, height=korkeus, width=leveys, yscrollcommand=vieritin.set)
    laatikko.configure(state="disabled")
    laatikko.pack(side=tk.LEFT, expand=True, fill=tk.BOTH)
    vieritin.pack(side=tk.RIGHT, fill=tk.Y)
    vieritin.configure(command=laatikko.yview)
    return laatikko

def kirjoita_tekstilaatikkoon(laatikko, sisalto, tyhjaa=False):
    """
    Kirjoittaa rivin tekstiä valittuun tekstilaatikkoon. Tarvittaessa laatikko
    voidaan myös tyhjentää ennen kirjoitusta asettamalla tyhjaa-argumentin
    arvoksi True.

    :param widget laatikko: tekstilaatikko-objekti johon kirjoitetaan
    :param str sisalto: kirjoitettava teksti
    :param bool tyhjaa: tyhjätäänkö laatikko ensin
    """

    laatikko.configure(state="normal")
    if tyhjaa:
        try:
            laatikko.delete(1.0, tk.END)
        except tk.TclError:
            pass
    laatikko.insert(tk.INSERT, sisalto + "\n")
    laatikko.configure(state="disabled")

def luo_listalaatikko(kehys, leveys=80, korkeus=20):
    """
    Luo listalaatikon. Erona tekstilaatikkoon, listalaatikon rivit ovat
    yksittäisiä objekteja. Niitä voidaan siis valita hiirellä sekä poistaa ja
    lisätä yksitellen.

    :param widget kehys: kehys, jonka sisälle listalaatikko sijoitetaan
    :param int leveys: laatikon leveys merkkeinä
    :param int korkeus: laatikon korkeus riveinä
    :return: listalaatikko-objekti
    """

    laatikkokehys = luo_kehys(kehys, tk.TOP)
    vieritin = tk.Scrollbar(laatikkokehys)
    laatikko = tk.Listbox(laatikkokehys,
        height=korkeus,
        width=leveys,
        yscrollcommand=vieritin.set
    )
    laatikko.pack(side=tk.LEFT, expand=True, fill=tk.BOTH)
    vieritin.pack(side=tk.RIGHT, fill=tk.Y)
    vieritin.configure(command=laatikko.yview)
    return laatikko

def lisaa_rivi_laatikkoon(laatikko, sisalto, paikka=tk.END):
    """
    Lisää tekstirivin listalaatikkoon. Paikka voidaan antaa valinnaisena
    argumenttina, jolloin lisäys tapahtuu määritettyyn väliin. Jos parametria
    ei anneta, lisäys tehdään loppuun.

    :param widget laatikko: listalaatikko-objekti johon lisätään
    :param str sisalto: rivin sisältö
    :param int paikka: paikka johon rivi lisätään (valinnainen)
    """

    laatikko.insert(paikka, sisalto)

def poista_rivi_laatikosta(laatikko, indeksi):
    """
    Poistaa määritetyn rivin listalaatikosta. Rivi määritetään indeksillä.

    :param widget laatikko: listalaatikko-objekti josta poistetaan
    :param int indeksi: poistettavan rivin indeksi
    """

    laatikko.delete(indeksi)

def lue_valittu_rivi(laatikko):
    """
    Lukee listalaatikosta, mikä riveistä on valittu hiirellä. Palauttaa valitun
    rivin indeksin sekä sisällön. Jos mitään riviä ei ole valittu, palauttaa
    kaksi Nonea.

    :param widget laatikko: listalaatikko-objekti josta luetaan
    """

    valittu = laatikko.curselection()
    if valittu:
        sisalto = laatikko.get(valittu)
        return valittu[0], sisalto
    return None, None

def luo_tekstirivi(kehys, teksti):
    """
    Luo pienen tekstipätkän, jota voi käyttää tilatietojen esittämiseen, tai
    antamaan otsikoita käyttöliittymän eri osille.

    :param widget kehys: kehys, jonka sisälle tekstilaatikko sijoitetaan
    :param str teksti: näytettävä teksti
    :return: tekstiriviobjekti
    """

    rivi = tk.Label(kehys, text=teksti)
    rivi.pack(side=tk.TOP, fill=tk.BOTH)
    return rivi

def paivita_tekstirivi(rivi, teksti):
    """
    Päivittää tekstirivin sisällön.

    :param widget rivi: tekstiriviobjekti
    :param str teksti: uusi sisältö
    """

    rivi.configure(text=teksti)

def luo_tekstikentta(kehys):
    """
    Luo tekstikentän, johon käyttäjä voi syöttää tekstiä. Tekstikentän arvo
    voidaan lukea kutsumalla lue_kentan_sisalto-funktiota.

    :param widget kehys: kehys, jonka sisälle tekstikenttä sijoitetaan
    :return: tekstikenttäobjekti
    """

    kentta = tk.Entry(kehys)
    kentta.pack(side=tk.TOP, fill=tk.BOTH)
    return kentta

def lue_kentan_sisalto(kentta):
    """
    Lukee määritetyn syötekentän sisällön ja palauttaa sen.

    :param widget kentta: syötekenttä, jonka sisältö halutaan lukea
    :return: syötekentän sisältö merkkijonona
    """

    return kentta.get()

def tyhjaa_kentan_sisalto(kentta):
    """
    Tyhjentää määritetyn syötekentän sisällön.

    :param widget kentta: syötekenttä, jonka sisältö halutaan lukea
    """

    kentta.delete(0, len(kentta.get()))

def kirjoita_tekstikenttaan(kentta, sisalto):
    """
    Kirjoittaa määritettyyn syötekenttään sisältöä.

    :param widget kentta: syötekenttä, johon halutaan kirjoittaa
    :param str sisalto: kirjoitettava sisältö
    """

    kentta.insert(0, sisalto)

def luo_vaakaerotin(kehys, marginaali=2):
    """
    Luo vaakatason erottimen, jolla voidaan esim. erottaa selkeämmin
    käyttöliittymän osia toisistaan. Funktiolle voidaan lisäksi antaa toinen
    argumentti, joka kertoo paljonko ylimääräistä tyhjää laitetaan viivan
    molemmin puolin.

    :param widget kehys: kehys, johon erotin sijoitetaan
    :param int marginaali: ylimääräisen tyhjän määrä pikseleinä
    """

    erotin = Separator(kehys, orient="horizontal")
    erotin.pack(side=tk.TOP, fill=tk.BOTH, pady=marginaali)

def luo_pystyerotin(kehys, marginaali=2):
    """
    Luo pystysuoran erottimen, jolla voidaan esim. erottaa selkeämmin
    käyttöliittymän osia toisistaan. Funktiolle voidaan lisäksi antaa toinen
    argumentti, joka kertoo paljonko ylimääräistä tyhjää laitetaan viivan
    molemmin puolin.

    :param widget kehys: kehys, johon erotin sijoitetaan
    :param int marginaali: ylimääräisen tyhjän määrä pikseleinä
    """

    erotin = Separator(kehys, orient="vertical")
    erotin.pack(side=tk.TOP, fill=tk.BOTH, pady=marginaali)

def avaa_viesti_ikkuna(otsikko, viesti, virhe=False):
    """
    Avaa ponnahdusikkunan, jossa on viesti käyttäjälle. Viesti-ikkuna voidaan
    määritellä virhe-argumentilla virheikkunaksi, jolloin siinä näkyy eri
    kuvake. Ikkunalle annetaan otsikko ja viesti.

    :param str otsikko: ikkunan otsikko
    :param str viesti: ikkunaan kirjoitettava viesti
    :param bool virhe: totuusarvo, joka kertoo onko kyseessä virheviesti
    """

    if virhe:
        messagebox.showerror(otsikko, viesti)
    else:
        messagebox.showinfo(otsikko, viesti)

def avaa_hakemistoikkuna(otsikko, alkuhakemisto="."):
    """
    Avaa ikkunan, josta käyttäjä voi valita hakemiston. Hyödyllinen erityisesti
    datakansion lataamiseen. Ikkunalle tulee antaa otsikko, ja lisäksi sille
    voidaan määrittää mikä hakemisto aukeaa aluksi (oletuksena se hakemisto,
    josta ohjelma käynnistettiin). Funktio palauttaa polun käyttäjän valitsemaan
    hakemistoon merkkijonona.

    :param str otsikko: hakemistoikkunan otsikko
    :param str alkuhakemisto: hakemisto, joka avautuu ikkunaan
    :return: käyttäjän valitseman hakemiston polku
    """

    polku = filedialog.askdirectory(title=otsikko, mustexist=True, initialdir=alkuhakemisto)
    return polku

def avaa_tiedostoikkuna(otsikko, alkuhakemisto="."):
    """
    Avaa ikkunan, josta käyttäjä voi valita olemassaolevan tiedoston. Ikkunalle
    tulee antaa otsikko, ja lisäksi sille voidaan määrittää mikä hakemisto
    aukeaa aluksi (oletuksena se kansio mistä ohjelma käynnistettiin). Funktio
    palauttaa polun käyttäjän valitsemaan tiedostoon merkkijonona.

    :param str otsikko: tiedostoikkunan otsikko
    :param str alkuhakemisto: hakemisto, joka avautuu ikkunaan
    :return: käyttäjän valitseman tiedoston polku
    """

    polku = filedialog.askopenfilename(title=otsikko, initialdir=alkuhakemisto)
    return polku

def avaa_tallennusikkuna(otsikko, alkuhakemisto="."):
    """
    Avaa tallennusikkunan, jolla käyttäjä voi valita tallennettavalle
    tiedostolle sijainnin ja nimen. Ikkunalle tulee antaa otsikko, ja lisäksi
    sille voidaan määrittää mikä hakemisto aukeaa aluksi (oletuksena se
    hakemisto, josta ohjelma käynnistettiin). Funktio palauttaa polun käyttäjän
    nimeämään tiedostoon.

    :param str otsikko: tallennusikkunan otsikko
    :param str alkuhakemisto: hakemisto, joka avautuu ikkunaan
    :return: käyttäjän nimeämän tiedoston polku
    """

    polku = filedialog.asksaveasfilename(title=otsikko, initialdir=alkuhakemisto)
    return polku

def poista_elementti(elementti):
    """
    Poistaa määritetyn elementin käyttöliittymästä. Tarpeen, jos haluat
    käyttöliittymään tilapäisiä elementtejä.

    :param widget elementti: poistettava elementti
    """

    try:
        elementti.destroy()
    except AttributeError:
        elementti.get_tk_widget().destroy()

def luo_ali_ikkuna(otsikko):
    """
    Luo ali-ikkunan, jonka sisältöä voidaan muokata. Ali-ikkuna toimii samalla
    tavalla kuin kehys, eli siihen voidaan laittaa mitä tahansa muita
    käyttöliittymäkomponentteja. Ali-ikkuna voidaan piilottaa ja avata
    uudestaan käyttämällä näytä_ali_ikkuna- ja piilota_ali_ikkuna-funktioita.

    :param str otsikko: ali-ikkunan otsikko
    :return: luotu ali-ikkunaobjekti
    """

    ali = tk.Toplevel()
    ali.title(otsikko)
    ali.protocol("WM_DELETE_WINDOW", ali.withdraw)
    return ali

def nayta_ali_ikkuna(ali, otsikko=None):
    """
    Näyttää valitun ali-ikkunan.

    :param object ali: näytettävä ali-ikkuna
    """

    if otsikko:
        ali.title(otsikko)
    ali.deiconify()

def piilota_ali_ikkuna(ali):
    """
    Piilottaa valitun ali-ikkunan.

    :param object ali: piilotettava ali-ikkuna
    """

    ali.withdraw()

def kaynnista():
    """
    Käynnistää ohjelman. Kutsu tätä kun olet määritellyt käyttöliittymän.
    """

    ikkuna.mainloop()

def lopeta():
    """
    Sammuttaa ohjelman.
    """

    ikkuna.destroy()

if __name__ == "__main__":
    # Poistetaan kaksi pylint-varoitusta pois käytöstä, koska testikoodi
    # antaa ne aiheettomasti
    # pylint: disable=invalid-name,missing-docstring


    # funktio määritellään poikkeuksellisesti täällä, koska sitä ei ole
    # tarkoitus käyttää muuhun kuin kirjaston demoamiseen.
    def tervehdi():
        nimi = lue_kentan_sisalto(nimikentta)
        ammatti = lue_kentan_sisalto(ammattikentta)
        if nimi and ammatti:
            viesti = f"Terve {nimi}, olet kuulemma {ammatti}."
            kirjoita_tekstilaatikkoon(tekstilaatikko, viesti)
        else:
            avaa_viesti_ikkuna("Tietoja puuttuu",
                "Et antanut nimeä ja ammattia",
                virhe=True
            )

    testi_ikkuna = luo_ikkuna("Terve!")
    ylakehys = luo_kehys(testi_ikkuna, YLA)
    alakehys = luo_kehys(testi_ikkuna, YLA)
    nappikehys = luo_kehys(ylakehys, VASEN)
    syotekehys = luo_kehys(ylakehys, VASEN)
    tervehdysnappi = luo_nappi(nappikehys, "terve", tervehdi)
    lopetusnappi = luo_nappi(nappikehys, "lopeta", lopeta)
    nimiohje = luo_tekstirivi(syotekehys, "Nimi:")
    nimikentta = luo_tekstikentta(syotekehys)
    ammattiohje = luo_tekstirivi(syotekehys, "Ammatti:")
    ammattikentta = luo_tekstikentta(syotekehys)
    tekstilaatikko = luo_tekstilaatikko(alakehys, 34, 20)
    kaynnista()

Tämä on muuten sama kuin Spektriä pukkaa -lopputyössä käytettävä kirjasto, mutta tästä on poistettu matplotlib-tuki, jotta jonkun toisen aiheen valinnaiden ei tarvitse asentaa sitä pelkästään esimerkkejä testatakseen. Kirjastoa ei käydä sen tarkemmin läpi kuin siltä osin mitä esimerkissä tarvitaan. Muuten se jätetään kotitehtäväksi lopputyötä tehdessä.

Ihmemaan takaisinkutsut

Takaisinkutsua
käytettiin hyvin lyhyellä esittelyllä
listojen
järjestämisessä. Listan sort-
metodille
pystyttiin antamaan argumenttina
funktio
, jota käytettiin järjestämisen aikana
vertailuarvojen
saamiseen - näiden avulla siis pystyttiin valitsemaan minkä tiedon perusteella listan
alkiot
järjestetään. Esim:
kokoelma.sort(key=valitse_kesto, reverse=kaanna)
Erikoista tässä asetelmassa on siis se, että emme kutsu missään vaiheessa omassa koodissa valitse_kesto-funktiota - sitä kutsutaan silloin, kun ohjelman ohjaus on luovutettu tilapäisesti sort-metodille.
Argumentin
antaminen siis kertoo sort-metodille mitä funktiota sen tulee kutsua, kun sen tarvii saada vertailuarvo listan alkiolle. Koska argumenttien antamisesta vastaa sort-metodi, emme voi vaikuttaa siihen mitä funktiolle annetaan emmekä myöskään siihen mitä sen paluuarvolla tehdään. Takaisinkutsufunktioita tehtäessä onkin tärkeää selvittää hyvin tarkasti mitä argumentteja funktio saa ja mitä sen paluuarvolla tehdään, jotta voidaan asettaa oikea määrä
parametrejä
sekä
palauttaa
oikeanlainen arvo. Esimerkissä käytettyä funktiota katsomalla selviää, että sillä tulee olla yksi parametri (listan yksi alkio) ja se palauttaa yhden arvon:
def valitse_kesto(levy):
    return levy["kesto"]
Tämän asian kertaaminen on tärkeää, koska sama ilmiö toistuu käyttöliittymä- ja pelikirjastojen kanssa, mutta paljon laajempana. Niille on nimittäin tyypillistä se, että koko ohjelmaa ohjaava pääsilmukka sijaitsee jossain kirjaston syövereissä. Nykyisessä kokoelmaohjelmassa valikko-funktiossa oleva while True:-silmukka on siis pääohjelmasilmukka, ja tällaista ei tulla lainkaan näkemään koodissa kun se muutetaan käyttämään graafista kirjastoa. Ohjelman kulkua tullaan siis ohjaamaan ikään kuin ulkopuolelta. Syytäkään ei tarvi kauaa ihmetellä: pääsilmukan pitäisi pystyä reagoimaan siihen kun käyttäjä on vuorovaikutuksessa käyttöliittymän kanssa, joten siihen kuuluu aika paljon koodia. Tätä koodimäärää ei ole kauhean mielekästä alkaa itse kirjoittaa, joten se on parempi ulkoistaa kirjastolle.
Jos ohjelman kulun hallinta on poistettu ohjelmoijan omista kätösistä jonnekin mystisen kirjaston syövereihin, miten tässä päästään toteuttamaan yhtään mitään? Vastaus löytyy nimenomaan takaisinkutsufunktioista joita myös
käsittelijäfunktioiksi
kutsutaan. Ennen pääsilmukan käynnistämistä koodari voi kertoa kirjastolle millaiset
tapahtumat
ohjelmaa kiinnostavat. Tapahtuma tarkoittaa esim. sitä, kun pääsilmukka havaitsee käyttäjän tekevän jotain. Näihin tapahtumiin voidaan kiinnittää käsittelijäfunktio. Jos määritetty tapahtuma kohdataan, kutsutaan siihen kiinnitettyä käsittelijää.
Käyttöliittymäkirjastojen tapauksessa on yleistä, että kuhunkin aktiiviseen käyttöliittymäelementtiin kiinnitetään oma käsittelijä. Tämä tehdään siinä yhteydessä kun käyttöliittymän komponentit ylipäätään määritellään. Eli jos vaikka halutaan luoda nappi, siihen voidaan luomisen yhteydessä määrittää funktio, jota käyttöliittymäkirjasto kutsuu kun käyttäjä painaa nappia. Meidän yksinkertainen kirjastomme toteuttaa tämän siten, että siellä on tasan yksi napinluontifunktio, jolle annetaan kolme argumenttia:
  1. kehyselementti johon nappi sijoitetaan (ks. seuraava osio)
  2. napissa lukeva teksti (merkkijono)
  3. funktio joka toimii napin käsittelijänä
Korkealla tasolla ajateltuna se mitä tapahtuu kun graafista käyttöliittymää tarjoava ohjelma käynnistetään on siis seuraavanlainen prosessi:
  1. ohjelma määrittelee käyttöliittymän elementit käsittelijäfunktioineen
  2. ohjelma kutsuu funktiota, joka käynnistää käyttöliittymäkirjaston pääsilmukan
  3. käyttöliittymäkirjasto seuraa käyttäjän toimia
    1. käyttäjä tekee jotain, mikä kiinnostaa ohjelmaa (=
      tapahtuma
      , johon on kytketty
      käsittelijä
      )
    2. käyttöliittymäkirjasto kutsuu käsittelijäfunktiota, jolloin ohjaus palaa varsinaiselle ohjelmalle
    3. käsittelijäfunktion suorituksen päätyttyä ohjaus siirtyy takaisin käyttöliittymäkirjastolle
  4. ohjelmassa oleva käsittelijäfunktio kutsuu funktioita, joka sammuttaa käyttöliittymäkirjaston pääsilmukan ja ohjaus palautaa ohjelmalle
  5. ohjelma voi suorittaa lopetukseen liittyvät toimenpiteet (esim. datan tallennus)
  6. ohjelma päättyy

Käyttöliittymäsimulaattori

Jotta toimintaperiatteeseen saadaan hieman kosketusta, tutkitaan hetki oheista approksimaatiota siitä millainen käyttöliittymäkirjasto voisi olla. Esitetty koodi on moninkertaisesti yksinkertaisempi kuin oikea käyttöliittymäkirjasto, mutta käyttäytyy kuitenkin samanlaisella logiikalla. Kirjaston funktioilla voidaan siis määrittää nappeja, ja se voidaan käynnistää jolloin se keräilee "klikkauksia" (jotka tuotetaan tässä tapauksessa satunnaisina pistepareina hiiren lukemisen sijaan), ja suorittaa nappien toimintoja mikäli klikkaus osuu johonkin niistä.
kirjasto.py
import random
import sys
import time
import turtle as t

LEVEYS = 800
KORKEUS = 600
NAPPI_LEVEYS = 200
NAPPI_KORKEUS = 60

VASEN = 0
OIKEA = 1
YLA = 2
ALA = 3

ikkuna = []
tila = {
    "piirto": False,
    "kaynnissa": False
}


def luo_ikkuna(otsikko):
    """
    Luo "ikkunan" johon käyttöliittymän kehykset ja elementit voidaan kerätä.
    Tässä approksimaatiossa ikkuna on vain lista, johon elementit
    lisätään. Tämä funktio ainoastaan tyhjää olemassaolevan ikkunalistan.
    """
    
    ikkuna.clear()
    return ikkuna
    
def luo_kehys(isanta, puoli=VASEN):
    """
    Luo kehyksen. Tämä funktio hieman huijaa, ja lisää kehyksen suoraan
    ikkunaan riippumatta siitä mitä parametrien arvot ovat. Kirjasto ei siis
    tue sisäkkäisiä kehyksiä, eikä alekkaisia kehyksiä. 
    """

    kehys = []
    ikkuna.append(kehys)
    return kehys

def luo_nappi(kehys, teksti, toiminto):
    """
    Luo napin, eli lisää kehykseen nappia kuvaavan sanakirjan. Napin sijainti
    lasketaan kehyksen indeksistä ikkunan sisällä sekä kehyksessä jo olevien
    nappien lukumäärästä siten, että napin leveydeksi tulee NAPPI_LEVEYS ja korkeudeksi
    NAPPI_KORKEUS yksikköä.
    """
    
    vasen = ikkuna.index(kehys) * NAPPI_LEVEYS
    oikea = vasen + NAPPI_LEVEYS
    yla = len(kehys) * NAPPI_KORKEUS
    ala = yla + NAPPI_KORKEUS
    kehys.append({
        "vasen": vasen,
        "oikea": oikea,
        "yla": yla,
        "ala": ala,
        "teksti": teksti,
        "toiminto": toiminto
    })
    
def lue_klikkaus():
    """
    Funktio joka tuottaa uuden "klikkauksen". Toistaiseksi generoi satunnaisen
    pisteen joka on "ikkunan" rajojen sisällä.
    """
    
    x = random.randint(0, LEVEYS - 1)
    y = random.randint(0, KORKEUS - 1)
    return x, y
    
def tunnista_nappi(x, y, ikkuna):
    """
    Etsii mihin nappiin klikkaus osui ikkunan sisällä, jos mihinkään. 
    Mikäli klikkaus osui nappin rajojen sisälle, kutsuu nappiin kiinnitettyä
    toiminto-funktiota.
    """

    for kehys in ikkuna:
        for nappi in kehys:
            if nappi["vasen"] <= x <= nappi["oikea"]:
                if nappi["yla"] <= y <= nappi["ala"]:
                    funktio = nappi["toiminto"]
                    funktio()
                    return
    
def kaynnista():
    """
    Lukee klikkauksia ja tarkistaa osuiko klikkaus nappiin. Silmukkaa
    suoritetaan niin kauan kuin tilasanakirjassa oleva "kaynnissa" arvo on
    True. Mikäli piirto valittiin tehtäväksi ohjelman käynnistyksessä, 
    piirtää nappien alueet sekä klikkauspisteet näkyviin.
    """

    tila["kaynnissa"] = True
    if tila["piirto"]:
        nayta_ikkuna()
    while tila["kaynnissa"]:
        print(".", end="", flush=True)
        hiiri_x, hiiri_y = lue_klikkaus()
        if tila["piirto"]:
            t.up()
            t.setx(hiiri_x - LEVEYS / 2)
            t.sety(KORKEUS / 2 - hiiri_y)
            t.down()
            t.dot()
        tunnista_nappi(hiiri_x, hiiri_y, ikkuna)
        # lisätty jotta ohjelma ei pyöri liian nopeasti
        time.sleep(0.1)
    if tila["piirto"]:
        t.done()
        
def lopeta():
    """
    Asettaa tilasanakirjassa olevan lipun Falseksi, jolloin kaynnista-funktiossa
    pyörivä pääsilmukka katkeaa ja ohjelma päättyy.
    """
    
    tila["kaynnissa"] = False
    
def nayta_ikkuna():
    """
    Piirtää kuvan ikkunasta turtlella. 
    """
    
    t.up()
    t.setx(-1 * LEVEYS / 2)
    t.sety(KORKEUS / 2)
    t.down()
    t.forward(LEVEYS)
    t.right(90)
    t.forward(KORKEUS)
    t.right(90)
    t.forward(LEVEYS)
    t.right(90)
    t.forward(KORKEUS)
    t.right(90)
    for kehys in ikkuna:
        for nappi in kehys:
            t.up()
            t.setx(nappi["vasen"] - LEVEYS / 2)
            t.sety(KORKEUS / 2 - nappi["yla"])
            t.down()
            t.forward(NAPPI_LEVEYS)
            t.right(90)
            t.forward(NAPPI_KORKEUS)
            t.right(90)
            t.forward(NAPPI_LEVEYS)
            t.right(90)
            t.forward(NAPPI_KORKEUS)
            t.right(90)
    
try:
    if sys.argv[1].lower() in ["-p", "--piirto"]:
        tila["piirto"] = True
except IndexError:
    pass
        
    
    
    

Tärkeintä tässä approksimaatiossa on se, että sen voisi korvata em. ikkunasto-kirjastolla - määritettyjen funktioiden rajapinnat ovat nimittäin samat kirjastoa käyttävän moduulin näkökulmasta. Käyttöliittymäkirjastojen toiminnan ymmärtämiseksi on tarpeen tarkastella kahta tässä esiintyvää funktiota, sekä sitä miten niitä käytettäisiin varsinaisessa ohjelmassa. Tätä varten on luotu siis oheinen testiohjelma, joka luo muutaman napin sisältävän käyttöliittymän.
kirjastotesti.py
import kirjasto

def tulosta_aasi():
    print("aasi")
    
def tulosta_hemuli():
    print("hemuli")

ikkuna = kirjasto.luo_ikkuna("testi")
kehys = kirjasto.luo_kehys(ikkuna)
kirjasto.luo_nappi(kehys, "nappi 1", tulosta_aasi)
kirjasto.luo_nappi(kehys, "nappi 2", tulosta_hemuli)
kirjasto.luo_nappi(kehys, "lopeta", kirjasto.lopeta)
kirjasto.kaynnista()
print("terve, ja kiitos kaloista")

Koodin suoritus ei luo näkyvää ikkunaa, koska kirjasto ainoastaan simuloi oikean kirjaston toimintaa. Sen sijaan
terminaaliin
tulostuu pisteitä ja välillä "aasi" tai "hemuli" - yksi piste kuvaa yhtä klikkausta, ja sanan ilmestyminen tarkoittaa, että klikkaus osui johonkin määritellyistä napeista. Samaten ohjelma päättyy, kun klikkaus osuu lopetusnappiin. Suoritus voi siis näyttää esim tältä:
..................................aasi
............hemuli
..aasi
......................................................aasi
..................aasi
..terve, ja kiitos kaloista
Koska simulaattorin koodi on paljon yksinkertaisempaa, syy-seuraus-suhteet ovat myös helpompia seurata. Tarkastellaan erityisesti kahden kirjastossa olevan funktion toimintaa. Tavoitteena on siis ymmärtää miksi lopullinen ohjelma (eli kirjastotesti.py) toimii kuten se toimii. Ensimmäinen puoli on käyttöliittymän asettelu. Varsinaisen ohjelman näkökulmasta käyttöliittymä muodostuu kehyksistä (sarakkeita) ja napeista (rivejä sarakkeiden sisällä). Ohjelma voi siis luoda kehyksiä, ja tuupata uusia nappeja niihin. Kirjaston puolella nappien luomisesta vastaa luo_nappi-funktio.
def luo_nappi(kehys, teksti, toiminto):

    vasen = ikkuna.index(kehys) * NAPPI_LEVEYS
    oikea = vasen + NAPPI_LEVEYS
    yla = len(kehys) * NAPPI_KORKEUS
    ala = yla + NAPPI_KORKEUS
    kehys.append({
        "vasen": vasen,
        "oikea": oikea,
        "yla": yla,
        "ala": ala,
        "teksti": teksti,
        "toiminto": toiminto
    })
Tämä funktio laskee napin varsinaisen sijainnin ikkunan sisällä ja tallentaa napin reunoja vastaavat x- ja y-arvot
sanakirjaan
. Tässä siis rajataan käyttöliittymän alue, joka kuuluu tälle napille. Yhden napin leveys on 200 yksikköä ja korkeus 60 yksikköä, sijainti perustuu siihen mikä on kehyksen
indeksi
ikkunan sisällä, sekä siihen montako nappia kehyksessä jo on. Toinen erittäin tärkeä asia joka talletetaan sanakirjaan on toiminto-
parametrin
arvo, joka on siis
funktio
. Tämä funktio siis suorittaa varsinaisen nappiin sidotun toiminnon - mutta vasta sitten kun nappia painetaan! Funktiota ei siis kutsuta vielä.
Varsinaisen ohjelman puolella nappi luodaan siis luo_nappi-funktiota kutsumalla, kun ensin ollaan määritelty toiminnoksi annettava funktio:
def tulosta_aasi():
    print("aasi")

ikkuna = kirjasto.luo_ikkuna("testi")
kehys = kirjasto.luo_kehys(ikkuna)
kirjasto.luo_nappi(kehys, "nappi 1", tulosta_aasi)
Tärkeää tässä on kiinnittää huomiota siihen, että funktiota käsitellään kuin
muuttujaa
: sitä ei siis kutsuta, se vain annetaan
argumenttina
. Esimerkkiohjelmassa luodaan kolme nappia, jonka jälkeen meillä on alla olevaa kuvaa vastaa "käyttöliittymä".
"Ikkunan" asettelu
Napit ovat siis ikkunaan merkittyjä alueita, ja hiiren klikkaaminen kursorin ollessa napin alueen sisällä aiheuttaa napin painamisen. Tämä on se vaihe, missä ohjelman kontrolli luovutetaan kirjastolle - tarkalleen ottaen siellä olevalle kaynnista-funktiolle. Funktiosta on poistettu hiukan ylimääräistä tavaraa, jotta logiikka näkyy selkeämmin:
def tunnista_nappi(x, y, ikkuna):
    for kehys in ikkuna:
        for nappi in kehys:
            if nappi["vasen"] <= x <= nappi["oikea"]:
                if nappi["yla"] <= y <= nappi["ala"]:
                    funktio = nappi["toiminto"]
                    funktio()
                    return

def kaynnista():
    tila["kaynnissa"] = True
    while tila["kaynnissa"]:
        print(".", end="", flush=True)
        hiiri_x, hiiri_y = lue_klikkaus()
        tunnista_nappi(ikkuna, hiiri_x, hiiri_y)
        # lisätty jotta ohjelma ei pyöri liian nopeasti
        time.sleep(0.1)
Oikean käyttöliittymäkirjaston vastaava funktio on tietenkin paljon monimutkaisempi, mutta pohjimmillaan siinä tehdään samat asiat:
  1. luetaan hiiren klikkauksen sijainti
  2. etsitään osuuko klikkaus jonkin käyttöliittymäelementin sisälle
    1. jos osuu, suoritetaan toiminto ja
    2. lopetetaan etsintä
Tätä siis toistetaan ikuisessa silmukassa kunnes ohjelman suoritus päättyy. Meidän simulaattorissamme vaihe 1 hoituu kutsumalla lue_klikkaus-funktiota, josta saadaan (kuvitellun) klikkauksen x- ja y-koordinaatit. Vaihe 2 tapahtuu käymällä läpi kaikki kehykset sekä niissä olevat nappeja kuvaavat sanakirjat, ja vertaamalla niissä määriteltyjä rajoja klikattuun pisteeseen. Mikäli piste osuu rajojen sisällä, napin toiminto suoritetaan ottamalla sanakirjan "toiminto"
avaimesta
viittaus
kutsuttavaan funktioon, ja kutsutaan sitä (ilman argumentteja).
Tärkeintä tässä on siis nähdä konkreettisesti millaisessa kontekstissa napin toiminnoksi annettua funktiota tullaan lopulta kutsumaan. Kuten tästä nähdään, funktiolle annettavat argumentit määritellään kutsun yhteydessä (ja tässä tapauksessa niitä ei ole). Syntaksista myös ilmenee, että mikäli muuttuja sisältää funktion ja sen perään laitetaan kutsusulut, muuttuu kyseinen rivi muuttujaan talletetun funktion
kutsumiseksi
. Tässä vaiheessa siis kontrolli palaa varsinaisen ohjelman puolelle, ja tarkalleen siellä olevan
käsittelijäfunktion
sisälle, joka ensimmäisen napin tapauksessa olisi siis:
def tulosta_aasi():
    print("aasi")
Näinpä siis terminaaliin tulostuu aasi. Ajossa terminaaliin tulostuneet pisteet kuvaavat klikkauksia, riippumatta siitä osuiko hiiri johonkin nappiin tai ei. Kun ohjelma "sammutetaan" kutsumalla kirjaston lopeta-funktiota, kontrolli palaa varsinaiseen ohjelmaan ja jatkuu kaynnista-funktiokutsua seuraavalta riviltä, eli tältä riviltä - tästä syystä siis ohjelman päättyessä tulostuu "terve, ja kiitos kaloista":
print("terve, ja kiitos kaloista")
Kokonaisessa kirjastossa on lisätty vielä mahdollisuus näyttää visualisointi toiminnasta turtlen avulla. Voit laittaa tämän visualisoinnin päälle lisämäällä
komentoriviargumentin
-p tai --piirto ohjelman käynnistykseen:
python kirjastotesti.py --piirto
Huomaa, että napeissa ei lue mitään. Ylin nappi tulostaa aasin, toinen hemulin, ja kolmas lopettaa ohjelman. Voit pitää terminaalin näkyvissä turtle-ikkunan rinnalla, jolloin näet mitä sinne tulostuu kunkin klikkauksen kohdalla.
Toinen näppärä yksityiskohta: mikäli vaihdat ensimmäisen rivin importin siten, että se ottaakin käyttöön ikkunaston, testikoodi toimii suoraan, ja tuottaa oikean käyttöliittymän. Eli ensimmäiseksi riviksi tulisi:
import ikkunasto as kirjasto
Jolloin ohjelman suoritus tuottaakin oikean ikkunan. Ikkunan geometria on erilainen, koska elementtien asettelusta vastaa kirjasto, ei kirjastoa käyttävä ohjelma. Tästä onkin kerrottu tarkemmin seuraavan otsikon alla.
Kirjastotestin tuottama ikkuna, kun käytetään ikkunastoa kirjastosimulaattorin tilalla

Ohjeellinen käsittelijä

Käsittelijäfunktion asettaminen käyttöliittymäkomponenteille sekä erilaisille tapahtumille koodissa on tärkeä osa nykyajalle tyypillistä ohjelmointia. Kirjoitetaan tässä tehtävässä yksi käsittelijällä varustettu nappi kokeeksi.
Opittavat asiat:
käsittelijäfunktion
asettaminen käyttöliittymäkomponentille. Napin luominen ikkunasto-moduulin avulla.

Alustus:
Tehtävänannon lopussa näet koodin, jossa on pienen käyttöliittymän ensiaskeleet. Koodista löytyy valmiiksi funktio, jota on tarkoitus käyttää käsittelijänä, sekä ikkuna ja kehys. Koodista puuttuu vielä rivi, joka lisää ohjeikkunan avaavan napin kehykseen.

Haettu vastaus:
Vastaukseen haetaan yhtä koodiriviä joka lisää kehykseen napin, jonka tekstinä on merkkijono "Ohje" ja jonka käsittelijäfunktio on ainoa koodista löytyvä funktio. Luotua nappia ei ole tarpeen sijoittaa muuttujaan!

Resurssit:
ohjeikkuna.py
import ikkunasto as ik

def nayta_ohje():
    """
    Näyttää käyttöohjeen käyttäjälle.
    """

    ik.avaa_viesti_ikkuna(
        "Käyttöohje",
        "Tämä ohjelma sisältää toistaiseksi vain tämän käyttöohjeen..."
    )

def luo_ikkuna():
    ikkuna = ik.luo_ikkuna("Huikea ohjelma")
    kehys = ik.luo_kehys(ikkuna, ik.YLA)
    # kirjoita tähän koodirivi joka luo ohjenapin
    ik.kaynnista()

if __name__ == "__main__":
    luo_ikkuna()


Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Laatikoita ja pakkaamista

Ennen syventymistä toimintojen toteuttamiseen käsittelijäfunktioilla on syytä tutkia miten käyttöliittymä määritellään ohjelmakoodilla. TKinter käyttää menetelmää, jossa käyttöliittymä voidaan jakaa kehyksiin ja varsinaisiin komponentteihin. Kehys on vähän kuin Pythonin
lista
, eli se voi sisältää muita komponentteja - myös muita kehyksiä. Asettelu perustuu pakkaamiseen jotain seinää vasten (tämä ei tosin ole ainoa vaihtoehto). Komponentille siis määritetään suunta, mihin se pyritään työntämään. Esimerkiksi jos komponentin pakkaussuunta on ylöspäin, se pyrkii olemaan niin ylhäällä kehyksessään kuin mahdollista. Komponentit pakataan lisäysjärjestyksessä, joten ensimmäisenä pakattu komponentti on lähimpänä sitä reunaa jota vasten se on pakattu, toisena pakattu tämän "päällä".
Esimerkki pakkaamisesta, nuolet kuvaavat pakkaussuuntaa
Yleisesti ottaen kaikki yhden kehyksen komponentit kannattaa pakata samaan suuntaan jotta käyttöliittymään ei jää hölmön näköisiä aukkoja. Yksinkertaisuuden nimissä käyttöliittymäkirjastomme pakkaa aina kehyksen sisällä olevat komponentit yläreunaa vasten - ainoastaan itse kehysten pakkausuuntaan voi vaikuttaa funktioiden argumenteilla. Kirjasto myös piilottaa joitain mahdollisia asetuksia joilla asetteluun voisi TKinterissä vaikuttaa, eli sitä minkä näköisiä käyttöliittymiä voidaan luoda on rajoitettu aika paljon. TKinter ei kyllä muutenkaan ole paras kirjasto, jos haluaa oikeasti hienon näköisiä käyttöliittymiä. Esim. PySide 2 kääntää huomattavasti monipuolisemman (ja monimutkaisemman) Qt-käyttöliittymäkirjaston Pythonille.
Alla on esitetty funktio, joka luo kokoelmaohjelman uuden hienon graafisen käyttöliittymän komponentit sekä kuva miltä tämä käyttöliittymä näyttää (Linuxilla). Koodiin on myös lisätty lopeta-funktio, joka toimii lopetusnapin
käsittelijänä
.
import ikkunasto as ik

def lopeta():
    ik.lopeta()

def luo_ikkuna():
    ikkuna = ik.luo_ikkuna("Kokoelmaohjelma 0.1 alpha")
    nappikehys = ik.luo_kehys(ikkuna, ik.VASEN)
    kokoelmakehys = ik.luo_kehys(ikkuna, ik.VASEN)
    latausnappi = ik.luo_nappi(nappikehys, "Lataa", lataa_kokoelma)
    rakennusnappi = ik.luo_nappi(nappikehys, "Rakenna", rakenna_kokoelma)
    tallennusnappi = ik.luo_nappi(nappikehys, "Tallenna", tallenna_kokoelma)
    ik.luo_vaakaerotin(nappikehys, 5)
    lisaysnappi = ik.luo_nappi(nappikehys, "Lisää", lisaa)
    poistonappi = ik.luo_nappi(nappikehys, "Poista", poista)
    muokkausnappi = ik.luo_nappi(nappikehys, "Muokkaa", muokkaa)
    ik.luo_vaakaerotin(nappikehys, 5)
    lopetusnappi = ik.luo_nappi(nappikehys, "Lopeta", lopeta)
    kokoelmalaatikko = ik.luo_listalaatikko(kokoelmakehys)
    ik.kaynnista()

if __name__ == "__main__":
    #lahde, kohde = lue_argumentit(sys.argv)
    try:
        luo_ikkuna()
    except KeyboardInterrupt:
        print("Ohjelma keskeytettiin, kokoelmaa ei tallennettu")
Käyttöliittymä näyttää tältä
Napinluontifunktiot ja muut pääasiassa kertovat palauttavansa
objektin
. Tällä hetkellä ne otetaan kaikki talteen
muuttujiin
, jotta niihin voidaan viitata myöhemmin. Emme ole tosin vielä miettineet tarvitseeko niihin viitata. Kehyksiin kyllä selkeästi viitataan jo tämän funktion sisällä, mutta nappeihin ei. Erottimet taas eivät ole aktiivisia komponentteja, joten kirjasto ei edes vaivaudu palauttamaan niitä. Toinen huomio on, että koodi voidaan tällä hetkellä ajaa, mutta napit eivät pääasiassa toimi (paitsi lopetusnappi). Pääohjelmaa on muutettu kutsumaan luo_ikkuna-funktiota aiemman valikko-funktion sijaan, ja komentoriviargumenttien lukeminen on toistaiseksi kommentoitu ulos.

Uudenlaista tiedonvälitystä

Syytä sille miksi napit eivät toimi ei tarvi etsiä kovin kaukaa. Ikkunaston luo_nappi-funktion
dokumenttimerkkijono
kertoo seuraavaa help-funktiolla katsottuna:
luo_nappi(kehys, teksti, kasittelija)
    Luo napin, jota käyttäjä voi painaa. Napit toimivat käsittelijäfunktioiden
    kautta. Koodissasi tulee siis olla määriteltynä funktio, jota kutsutaan
    aina kun käyttäjä painaa nappia. Tämä funktio ei saa lainkaan argumentteja.
    Funktio annetaan tälle funktiokutsulle kasittelija-argumenttina. Esim.

    def aasi_nappi_kasittelija():
        # jotain tapahtuu

    luo_nappi(kehys, "aasi", aasi_nappi_kasittelija)

    Napit pakataan aina kehyksensä ylälaitaa vasten, joten ne tulevat näkyviin
    käyttöliittymään alekkain. Jos haluat asetella napit jotenkin muuten, voit
    katsoa tämän funktion koodista mallia ja toteuttaa vastaavan
    toiminnallisuuden omassa koodissasi. Jos laajenna-argumentiksi annetaan
    True, nappi käyttää kaiken jäljellä olevan tyhjän tilan kehyksestään.

    :param widget kehys: kehys, jonka sisälle nappi sijoitetaan
    :param str teksti: napissa näkyvä teksti
    :param function kasittelija: funktio, jota kutsutaan kun nappia painetaan
    :return: palauttaa luodun nappiobjektin
Käsittelijäfunktio
ei saa siis lainkaan
argumentteja
, kun taas olemassaolevat
funktiot
odottavat niitä saavansa. Niitä ei voi siis suoraan käyttää käsittelijöinä. Vanhoja funktioita ei välttämättä kannata alkaa heti purkamaan. Esim lataa_kokoelma tekee edelleen työnsä aivan hyvin. Sille pitää vain saada annettua kokoelmatiedoston
polku
jotain muuta kautta. Hieman tutkimalla selviää, että ikkunastossa on oma funktio tiedostojen valitsemiselle: avaa_tiedostoikkuna. Muutetaan siis latausnapin käsittelijäksi uusi funktio, joka kutsuu lataa_kokoelma-funktiota saatuaan polun avaa_tiedostoikkuna-funktiolta. Vastaava voidaan tehdä kokoelman rakentamiselle (kumpikin avaa erilaisen valintaikkunan). Poistetaan myös input-funktiokutsu rakenna_kokoelma-funktiosta ja muutetaan kansio
parametriksi
.
def rakenna_kokoelma(kansio):
    try:
        kokoelma = nuuskija.lue_kokoelma(kansio)
    except FileNotFoundError:
        print("Kansiota ei löytynyt")
    return kokoelma

def avaa_latausikkuna():
    polku = ik.avaa_tiedostoikkuna("Valitse kokoelmatiedosto (JSON)")
    kokoelma = lataa_kokoelma(polku)

def avaa_rakennusikkuna():
    polku = ik.avaa_hakemistoikkuna("Valitse kokoelman juurikansio")
    kokoelma = rakenna_kokoelma(polku)
Tässä on nyt tosin pienoinen ongelma: käsittelijäfunktio ei myöskään voi palauttaa mitään, joten miten kokoelma, joka nyt on paikallisessa muuttujassa, saadaan näkymään muualla ohjelmassa? Tässä auttaa palauttaa mieleen, että sekä
lista
että
sanakirja
ovat
muuntuvia
. Jos
pääohjelmatasolla
on määritelty muuntuva
objekti
, sitä voidaan käsitellä ohjelman kaikissa funktioissa. Tässä tapauksessa tehdään kaukaa viisaasti sanakirja, jonka
avaimiin
voidaan sijoittaa muitakin objekteja joita saatetaan joutua jakamaan.
komponentit = {
    "kokoelma": []
}
Huomion arvoista on, että Pylint tulee valittamaan tästä (tosin tarkistimissa tämä valitus on otettu pois päältä), koska se pitää tätä sanakirjaa
vakiona
, koska se on määritelty pääohjelmassa. Tätä objektia on kuitenkin tarkoitus muutella suorituksen aikana, joten nimen kirjoittaminen isolla antaisi siitä väärän kuvan. Muutetaan lataus- ja rakennusfunktiot sijoittamaan kokoelma tähän sanakirjaan:
def rakenna_kokoelma(kansio):
    try:
        komponentit["kokoelma"] = nuuskija.lue_kokoelma(kansio)
    except FileNotFoundError:
        print("Kansiota ei löytynyt")

def lataa_kokoelma(tiedosto):
    try:
        with open(tiedosto, encoding="UTF-8") as lahde:
            komponentit["kokoelma"] = json.load(lahde)
    except (IOError, json.JSONDecodeError):
        print("Tiedoston avaaminen ei onnistunut. Aloitetaan tyhjällä kokoelmalla")
        komponentit["kokoelma"] = []

def avaa_latausikkuna():
    polku = ik.avaa_tiedostoikkuna("Valitse kokoelmatiedosto (JSON)")
    lataa_kokoelma(polku)
    tulosta(komponentit["kokoelma"])

def avaa_rakennusikkuna():
    polku = ik.avaa_hakemistoikkuna("Valitse kokoelman juurikansio")
    rakenna_kokoelma(polku)
    tulosta(komponentit["kokoelma"])
Funktioista ovat poistuneet return-lauseet, joten myös vastaavat sijoitukset tulee poistaa. Kokoelma saadaan nyt siis ladattua (tai rakennettua), joten se pitäisi enää saada näkymään käyttöliittymässä. Tätä varten on olemasa lisaa_rivi_laatikkoon-funktio, mutta sille pitäisi antaa argumenttina laatikko, johon rivi lisätään, ja rivin sisältö. Tällä hetkellä laatikko on olemassa vain luo_ikkuna-funktiossa, joten se pitänee lisätä tähän uuteen sanakirjaan. Uudelleenkirjoitetaan tulosta-funktio siten, että se tulostaa terminaalin sijaan listalaatikkoon käyttöliittymässä.
def muotoile_rivi(levy, i):
    return "{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"]
    )

def tulosta(kokoelma):
    for i, levy in enumerate(kokoelma):
        ik.lisaa_rivi_laatikkoon(komponentit["laatikko"], muotoile_rivi(levy, i + 1))
Ikkunan luonnissa listalaatikko pitää tietenkin tallentaa sanakirjaan, mikä tehdään näin komponentit["laatikko"] = ik.luo_listalaatikko(kokoelmakehys). Yksittäisen rivin muotoilu on omassa funktiossaan, koska ennakoimme, että sitä saattaa tarvita myös rivin päivittämiseen kun levyn tietoja muutetaan. Nyt saadaan aikaan kiva tulostus.
Tulostus ikkunaan näyttää tältä

Ponnahtavia ikkunoita

Tässä osiossa on paljon koodia, mutta ei lopulta kovin montaa asiaa. Tavoitteena on saada levyjen lisäys toimimaan. Koska tämä tehtiin aiemmin
tekstisyötteillä
, muutoksia pitää tehdä aika laajasti. Ajatus on kuitenkin, että käyttöliittymän Lisää-napin painaminen avaisi erillisen ikkunan johon levyn tiedot voi syöttää. Levy tallennetaan kokoelmaan kun ikkuna suljetaan - jos tiedot ovat kelvollisia. Muuten avataan virheviesti-ikkuna ja annetaan käyttäjälle mahdollisuus korjata virhe.
Kirjastosta löytyy muutama ali-ikkunoihin liittyvä
funktio
. Ali-ikkuna on siis tapa, jolla saadaan avattua toinen ikkuna pääikkunan päälle. Niihin voidaan sijoittaa kehyksiä ja komponentteja samalla tavalla kuin pääikkunaankin. Ali-ikkunan voi piilottaa ja tuoda esiin funktioilla. Hyvä tapa on siis luoda ikkuna heti ohjelman alussa, ja piilottaa se kun sitä ei tarvita. Tämä siis sen sijaan, että luotaisiin koko ikkuna joka kerta kokonaan uudestaan! Ikkuna sisältää tekstikenttiä ja niihin liittyviä otsikoita. Koko komeus luodaan luo_ikkuna-funktiossa:
def luo_ikkuna():
    # Pääikkunan luonti
    ikkuna = ik.luo_ikkuna("Kokoelmaohjelma 0.1 alpha")
    nappikehys = ik.luo_kehys(ikkuna, ik.VASEN)
    kokoelmakehys = ik.luo_kehys(ikkuna, ik.VASEN)
    latausnappi = ik.luo_nappi(nappikehys, "Lataa", avaa_latausikkuna)
    rakennusnappi = ik.luo_nappi(nappikehys, "Rakenna", avaa_rakennusikkuna)
    tallennusnappi = ik.luo_nappi(nappikehys, "Tallenna", avaa_tallennusikkuna)
    ik.luo_vaakaerotin(nappikehys, 5)
    lisaysnappi = ik.luo_nappi(nappikehys, "Lisää", avaa_lisayslomake)
    poistonappi = ik.luo_nappi(nappikehys, "Poista", poista)
    muokkausnappi = ik.luo_nappi(nappikehys, "Muokkaa", muokkaa)
    ik.luo_vaakaerotin(nappikehys, 5)
    lopetusnappi = ik.luo_nappi(nappikehys, "Lopeta", lopeta)
    komponentit["laatikko"] = ik.luo_listalaatikko(kokoelmakehys)

    # Ali-ikkunan luonti
    levylomake = ik.luo_ali_ikkuna("Levyn tiedot")
    kenttakehys = ik.luo_kehys(levylomake, ik.YLA)
    nappikehys = ik.luo_kehys(levylomake, ik.YLA)
    ohjekehys = ik.luo_kehys(kenttakehys, ik.VASEN)
    syotekehys = ik.luo_kehys(kenttakehys, ik.VASEN)
    ik.luo_tekstirivi(ohjekehys, "Artisti")
    komponentit["lomake_artisti"] = ik.luo_tekstikentta(syotekehys)
    ik.luo_tekstirivi(ohjekehys, "Albumi")
    komponentit["lomake_albumi"] = ik.luo_tekstikentta(syotekehys)
    ik.luo_tekstirivi(ohjekehys, "Kpl N")
    komponentit["lomake_kpl_n"] = ik.luo_tekstikentta(syotekehys)
    ik.luo_tekstirivi(ohjekehys, "Kesto (HH:MM:SS)")
    komponentit["lomake_kesto"] = ik.luo_tekstikentta(syotekehys)
    ik.luo_tekstirivi(ohjekehys, "Julkaisuvuosi")
    komponentit["lomake_vuosi"] = ik.luo_tekstikentta(syotekehys)
    ik.luo_nappi(nappikehys, "Tallenna", tallenna_lomake)
    ik.piilota_ali_ikkuna(levylomake)
    komponentit["levylomake"] = levylomake
    ik.kaynnista()
Viittaukset lomakkeen kenttiin ja itse lomakkeeseen tarvitaan komponentit-
sanakirjaan
, jotta kenttien sisältö voidaan lukea muualla ohjelmassa, ja jotta ikkuna voidaan piilottaa sekä tuoda esiin. Samalla Lisää-napin
käsittelijäfunktioksi
vaihdetaan uusi funktio, joka avaa lisäyslomakkeen. Vastaavasti tehdään myös tallennusnapille oma käsittelijä.
def avaa_tallennusikkuna():
    polku = ik.avaa_tallennusikkuna("Valitse tallennettava tiedosto")
    tallenna_kokoelma(komponentit["kokoelma"], polku)

def avaa_lisayslomake():
    ik.nayta_ali_ikkuna(komponentit["levylomake"], "Lisää levy")

def tallenna_lomake():
    ik.piilota_ali_ikkuna(komponentit["levylomake"])
Näillä eväillä lomake saadaan auki ja kiinni, joten voidaan katsoa miltä se näyttää. Ohjemerkkijonot eivät ihan osu kenttien kohdalle, mutta olkoot, niitä ei aleta tässä säätämään paikoilleen.
Levyn tietojen syöttölomake
Seuraavaksi lomake pitäisi saada tekemään jotain. Tämä vaatii hieman päätöksentekoa ja suunnittelua. Olemme päättäneet käyttää samaa lomaketta lisäämiseen ja muokkaamiseen. Olemme myös päättäneet, että tallennus tehdään ikkunan sulkemisen yhteydessä (missäs muuallakaan?) Tieto siitä onko lomake avattu lisäystä vai muokkausta varten pitäisi siis jotenkin kuljettaa tallenna_lomake-funktiolle. Mekanismi on sama kuin se, millä kokoelmalistaa kuskataan pitkin ohjelman käsittelijäfunktioita: tungetaan tieto siitä mitä ollaan tekemässä
sanakirjaan
. Eritellään samalla kokoelma-lista ja tämä uusi informaatio toiseen sanakirjaan, ja jätetään komponentit-sanakirjaan pelkästään viittaukset varsinaisiin käyttöliittymäelementteihin.
EI_VALITTU = 0
LISAA = 1
MUOKKAA = 2

komponentit = {
    "laatikko": None,
    "levylomake": None,
    "lomake_artisti": None,
    "lomake_albumi": None,
    "lomake_kpl_n": None,
    "lomake_kesto": None,
    "lomake_julkaisuvuosi": None,
}

tila = {
    "kokoelma": [],
    "toiminto": EI_VALITTU
}
Toteutetaan eri toimintojen erottaminen
vakioilla
. Näiden numeroarvoilla ei ole merkitystä, mutta nimetyt numerot ovat tällaisen informaation esittämiseen kätevämpiä kuin
merkkijonot
saati sitten paljaat numerot. Olemme myös tallentaneet komponenttisanakirjaan None jokaisen
avaimen
kohdalle. Tämä ei ole pakollista, mutta tällä halutaan esittää heti ohjelman alussa mihin komponentteihin sanakirjan kautta voi viitata. Hyödyntäen tila-sanakirjassa olevaa toiminto-informaatiota voidaan jatkaa lomakkeen käsittelyä:
def avaa_lisayslomake():
    ik.nayta_ali_ikkuna(komponentit["levylomake"], "Lisää levy")
    tila["toiminto"] = LISAA

def tallenna_lomake():
    if tila["toiminto"] == LISAA:
        onnistui = lisaa(tila["kokoelma"])
        paikka = len(tila["kokoelma"]) - 1
    elif tila["toiminto"] == MUOKKAA:
        onnistui = muokkaa(tila["kokoelma"])
    else:
        return

    if onnistui:
        ik.lisaa_rivi_laatikkoon(
            komponentit["laatikko"],
            muotoile_rivi(tila["kokoelma"][paikka], paikka + 1), paikka
        )
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_artisti"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_albumi"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_kpl_n"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_kesto"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_vuosi"])
        ik.piilota_ali_ikkuna(komponentit["levylomake"])
        tila["toiminto"] = EI_VALITTU
Toiminto siis asetetaan kun lomake avataan ja sen arvoa tarkastellaan kun lomake suljetaan Tallenna-napilla. Samalla tässä on tehty lomakkeen sulkemiseen liittyvää lisäkäsittelyä. Lomake halutaan sulkea vasta kun käyttäjä antoi oikeanlaista tietoa. Samalla halutaan myös pyyhkiä lomakkeen kentät tyhjiksi, jotta ne eivät ole siellä kummittelemassa seuraavalla avauskerralla. Onnistuneen tallennuksen tapahtuessa levy pitää lisätä myös käyttöliittymän listanäkymään. Toinen vaihtoehto olisi tietenkin tyhjentää koko lista ja kutsua tulosta-funktiota, joka tulostaisi koko kokoelman uudestaan, mutta tässä on aika paljon turhaa työtä. Varsinainen lisäysfunktio muuttuu itse asiassa vähän laajemmaksi rivien määrän puolesta.
def tarkista_kesto(kesto):
    return kesto

def lisaa(kokoelma):
    artisti = ik.lue_kentan_sisalto(komponentit["lomake_artisti"])
    albumi = ik.lue_kentan_sisalto(komponentit["lomake_albumi"])
    try:
        n = int(ik.lue_kentan_sisalto(komponentit["lomake_kpl_n"]))
    except ValueError:
        ik.avaa_viesti_ikkuna("Virhe tiedoissa", "Kappaleiden lukumäärän on oltava kokonaisluku", virhe=True)
        return False

    try:
        kesto = tarkista_kesto(ik.lue_kentan_sisalto(komponentit["lomake_kesto"]))
    except ValueError:
        ik.avaa_viesti_ikkuna("Virhe tiedoissa", "Keston on oltava muodossa HH:MM:SS", virhe=True)
        return False

    try:
        vuosi = int(ik.lue_kentan_sisalto(komponentit["lomake_vuosi"]))
    except ValueError:
        ik.avaa_viesti_ikkuna("Virhe tiedoissa", "Julkaisuvuoden on oltava kokonaisluku", virhe=True)
        return False

    kokoelma.append({
        "artisti": artisti,
        "albumi": albumi,
        "kpl_n": n,
        "kesto": kesto,
        "julkaisuvuosi": vuosi
    })
    return True
Syy on virheviesteissä: niissä halutaan nyt mainita erikseen missä kentässä virhe on, joten jokainen tarvii oman try-exceptin. Virheestä viestitään nyt kirjaston tarjoamalla viesti-ikkuna-toiminnolla, jolla voidaan tehdä erillisiä viesti-ikkunoita. Viimeinen argumentti, joka on selkeyden nimissä annettu
avainsana-argumenttina
kertoo kirjastolle, että ikkunassa tulisi käyttää virheestä kertovaa kuvaketta. Lomakkeen kentät saadaan luettua lue_kentan_sisalto-funktiolla, jota varten tarvitaan siis komponentit-
sanakirjasta
viittaukset kenttiin - tämä siis palauttaa kentän sisällön merkkijonona. Huomattavaa on, että tarkista_kesto ei edelleenkään oikeasti tee mitään, mutta ainakin nyt se käsitellään mikäli joskus koittaa päivä jolloin se tekee jotain.
Täytetty lisäyslomake, kokoelma näkyy pääikkunassa
Kokoelma lisäyksen jälkeen

Helpotusta korjaustöihin

Levyjen poisto kokoelmasta oli aiemmin hyvin kankeaa: levyn valintaan vaadittiin, että käyttäjä kirjoitti sekä albumin että artistin nimen. Nykymaailmassa olisi kuitenkin mukavampaa, jos poistettavan levyn voisi valita suoraan klikkaamalla käyttöliittymässä olevasta luettelosta. Juuri tätä varten olemme käyttäneet pelkän tekstilaatikon sijaan listalaatikkoa, jossa jokainen rivi on klikattava kokonaisuus. Kirjastossa on tätä varten oma
funktio
lue_valittu_rivi. Funktio palauttaa valitun rivin (jos valittu) indeksin ja sisällön. Lisäksi kirjastossa on funktio rivin poistamiseen. Näin olleen poista-funktiosta tuleekin aiempaa huomattavasti yksinkertaisempi:
def poista():
    valittu, sisalto = ik.lue_valittu_rivi(komponentit["laatikko"])
    if valittu != None:
        tila["kokoelma"].pop(valittu)
        ik.poista_rivi_laatikosta(komponentit["laatikko"], valittu)
Tässä käytetään nyt pop-
metodia
poistamaan
alkio
listasta
, koska halutaan poistaa indeksin eikä sisällön perusteella. Todettakoon myös, että tämä metodi myös palauttaa poistamansa alkion - nyt sillä ei vain tehdä mitään. Viimeinen rivi puolestaan poistaa levyn käyttöliittymän listanäkymästä. Ainoaksi ongelmaksi jää se, että numerointiin tulee reikä. Asia korjataan tällä kertaa laiskasti, eli poistamalla numerointi kokoelman tulostuksesta. Jos numerointia ei poisteta, pitäisi kaikki poistokohdasta eteenpäin olevien levyjen tiedot tulostaa uudestaan. Tätä funktiota voidaan käyttää suoraan poistonapin
käsittelijänä
.
Levyn valintaa listalaatikosta voidaan käyttää myös muokkaamiseen. Tämä on yhdistelmä aiemmin tehtyä lisäystoimintoa, mistä lainataan muokkauslomake, sekä juuri tehtyä poistotoimintoa, josta lainataan levyn valinta. Tällä kertaa avataan sama ali-ikkuna kuin levyä lisätessä, mutta halutaan täyttää tekstikenttiin levyn olemassaolevat arvot. Lisäksi muokattu levy pitäisi saada näkymään vanhalla paikallaan eikä kokoelman lopussa. Kaiken kaikkiaan tässä tarvitaan jälleen kohtalaisesti päätöksentekoa siitä, mitä tapahtuu missä. Helpointa on lähteä liikkeelle siitä, miten lomake avataan:
def avaa_muokkauslomake():
    paikka = kirjoita_tiedot_lomakkeeseen()
    ik.nayta_ali_ikkuna(komponentit["levylomake"], "Muokkaa levyä")
    tila["toiminto"] = MUOKKAA
    tila["valittu"] = paikka
Lomake pitää täyttää tässä vaiheessa ennen kuin se näytetään. Tätä varten lie parasta tehdä erillinen funktio. Sovitaan myös, että valittu paikka listassa (eli levyn indeksi kokoelmassa) luetaan tuossa funktiossa ja palautetaan sieltä. Toinen tässä tehty päätös on tallettaa tila
sanakirjaan
valitun levyn indeksi. Tämä ihan vain siksi, että käyttäjä ei sotke kokoelmaa valitsemalla toisen levyn lomakkeen avaamisen jälkeen, jolloin uudet tiedot tallentuisivat väärän levyn päälle. Tuo mainittu uusi funktio näyttää tältä:
def kirjoita_tiedot_lomakkeeseen():
    valittu, sisalto = ik.lue_valittu_rivi(komponentit["laatikko"])
    levy = tila["kokoelma"][valittu]
    ik.kirjoita_tekstikenttaan(komponentit["lomake_artisti"], levy["artisti"])
    ik.kirjoita_tekstikenttaan(komponentit["lomake_albumi"], levy["albumi"])
    ik.kirjoita_tekstikenttaan(komponentit["lomake_kpl_n"], levy["kpl_n"])
    ik.kirjoita_tekstikenttaan(komponentit["lomake_kesto"], levy["kesto"])
    ik.kirjoita_tekstikenttaan(komponentit["lomake_vuosi"], levy["julkaisuvuosi"])
    return valittu
Nyt lomake saadaan siis auki, ja sinne ilmestyvät valitun levyn tiedot muokkausta varten.
Valitun levyn muokkauslomake, jossa vanhat tiedot valmiina
Lomakkeen tallennusnapin käsittelijä on jo olemassa lisäystoiminnon jäljiltä, mutta silloin tehty arvaus siitä miten muokkaus toimii ei ollut täysin riittävä. Tehdään siis hieman lisää töitä:
def tallenna_lomake():
    if tila["toiminto"] == LISAA:
        onnistui = lisaa(tila["kokoelma"])
        paikka = len(tila["kokoelma"]) - 1
    elif tila["toiminto"] == MUOKKAA:
        paikka = tila["valittu"]
        onnistui = muokkaa(tila["kokoelma"], paikka)
        if onnistui:
            ik.poista_rivi_laatikosta(komponentit["laatikko"], paikka)
            tila["valittu"] = None
    else:
        return

    if onnistui:
        ik.lisaa_rivi_laatikkoon(
            komponentit["laatikko"], muotoile_rivi(tila["kokoelma"][paikka]), paikka
        )
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_artisti"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_albumi"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_kpl_n"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_kesto"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_vuosi"])
        ik.piilota_ali_ikkuna(komponentit["levylomake"])
        tila["toiminto"] = EI_VALITTU
Paikka päätettiin siis lukea siitä tilasanakirjan arvosta, joka asetettiin "valittu"-
avaimeen
kun lomake avatiin. Muokkauksen tekee varsinaisesti muokkaa-funktio. Jos se raportoi muokkauksen onnistuneen, poistetaan laatikosta vanha rivi, jotta sen paikalle voidaan tulostaa uudet tiedot. Varsinainen lisäys ei sen sijaan ole muuttunut, joten siltä osin funktion suunnittelussa onnistuttiin aiemmin. Jäljelle jää enää varsinaisen muokkaa-funktion toteutus:
def lue_tiedot_lomakkeesta(levy):
    levy["artisti"] = ik.lue_kentan_sisalto(komponentit["lomake_artisti"])
    levy["albumi"] = ik.lue_kentan_sisalto(komponentit["lomake_albumi"])
    try:
        levy["kpl_n"] = int(ik.lue_kentan_sisalto(komponentit["lomake_kpl_n"]))
    except ValueError:
        ik.avaa_viesti_ikkuna("Virhe tiedoissa", "Kappaleiden lukumäärän on oltava kokonaisluku", virhe=True)
        return None

    try:
        levy["kesto"] = tarkista_kesto(ik.lue_kentan_sisalto(komponentit["lomake_kesto"]))
    except ValueError:
        ik.avaa_viesti_ikkuna("Virhe tiedoissa", "Keston on oltava muodossa HH:MM:SS", virhe=True)
        return None

    try:
        levy["julkaisuvuosi"] = int(ik.lue_kentan_sisalto(komponentit["lomake_vuosi"]))
    except ValueError:
        ik.avaa_viesti_ikkuna("Virhe tiedoissa", "Julkaisuvuoden on oltava kokonaisluku", virhe=True)
        return None

    return levy

def muokkaa(kokoelma, indeksi):
    levy = lue_tiedot(kokoelma[indeksi].copy())
    if levy:
        kokoelma[indeksi] = levy
        return True
    return False

def lisaa(kokoelma):
    levy = lue_tiedot_lomakkeesta({})
    if levy:
        kokoelma.append(levy)
        return True
    return False
Koska lisäys ja muokkaus molemmat tarvitsevat samanlaista lomakkeesta lukemista, siitä päätettiin tehdä oma funktio. Siksi alimpana näkyy myös miten lisaa-funktiota on muokattu käyttämään tätä uutta työkalua. Kaiken kaikkiaan kokoelmaohjelma näyttää lopulta tältä. Järjestämiseen liittyvät toiminnot jätettiin tällä kertaa toteuttamatta, koska tarkoitus oli pääasiassa näyttää miten funktioita sidotaan käyttöliittymäelementteihin. Vanha järjestysfunktio jää koodiin malliksi, josta sen voi halutessaan vaikka muokata toimimaan uuden käyttöliittymän kanssa... Yksi aika helppo tapa on tehdä jokaiselle sarakkeelle oma nappinsa, jota painamalla kokoelma järjestetään sen mukaan, ja uudestaan painamalla sama käänteisenä.
Lopullinen tiedosto, jota on vielä hieman siistitty Pylintin avulla (esim. poistettu turhat muuttujat ikkunan luonnista, koska nappeihin ei tarvi viitata niiden luomisen jälkeen).
kokoelma.py
import json
import math
import sys
import ikkunasto as ik
import nuuskija

EI_VALITTU = 0
LISAA = 1
MUOKKAA = 2

komponentit = {
    "laatikko": None,
    "levylomake": None,
    "lomake_artisti": None,
    "lomake_albumi": None,
    "lomake_kpl_n": None,
    "lomake_kesto": None,
    "lomake_julkaisuvuosi": None,
}

tila = {
    "kokoelma": [],
    "toiminto": EI_VALITTU
}

def valitse_artisti(levy):
    return levy["artisti"]

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"]

def lataa_kokoelma(tiedosto):
    try:
        with open(tiedosto, encoding="UTF-8") as lahde:
            tila["kokoelma"] = json.load(lahde)
    except (IOError, json.JSONDecodeError):
        print("Tiedoston avaaminen ei onnistunut. Aloitetaan tyhjällä kokoelmalla")
        tila["kokoelma"] = []

def tallenna_kokoelma(kokoelma, tiedosto):
    try:
        with open(tiedosto, "w", encoding="UTF-8") as kohde:
            json.dump(kokoelma, kohde)
    except IOError:
        print("Kohdetiedostoa ei voitu avata. Tallennus epäonnistui")

def tarkista_kesto(kesto):
    return kesto

def lue_tiedot_lomakkeesta(levy):
    levy["artisti"] = ik.lue_kentan_sisalto(komponentit["lomake_artisti"])
    levy["albumi"] = ik.lue_kentan_sisalto(komponentit["lomake_albumi"])
    try:
        levy["kpl_n"] = int(ik.lue_kentan_sisalto(komponentit["lomake_kpl_n"]))
    except ValueError:
        ik.avaa_viesti_ikkuna("Virhe tiedoissa", "Kappaleiden lukumäärän on oltava kokonaisluku", virhe=True)
        return None

    try:
        levy["kesto"] = tarkista_kesto(ik.lue_kentan_sisalto(komponentit["lomake_kesto"]))
    except ValueError:
        ik.avaa_viesti_ikkuna("Virhe tiedoissa", "Keston on oltava muodossa HH:MM:SS", virhe=True)
        return None

    try:
        levy["julkaisuvuosi"] = int(ik.lue_kentan_sisalto(komponentit["lomake_vuosi"]))
    except ValueError:
        ik.avaa_viesti_ikkuna("Virhe tiedoissa", "Julkaisuvuoden on oltava kokonaisluku", virhe=True)
        return None

    return levy

def muokkaa(kokoelma, indeksi):
    levy = lue_tiedot(kokoelma[indeksi].copy())
    if levy:
        kokoelma[indeksi] = levy
        return True
    return False

def lisaa(kokoelma):
    levy = lue_tiedot_lomakkeesta({})
    if levy:
        kokoelma.append(levy)
        return True
    return False

def poista():
    valittu, sisalto = ik.lue_valittu_rivi(komponentit["laatikko"])
    if valittu != None:
        tila["kokoelma"].pop(valittu)
        ik.poista_rivi_laatikosta(komponentit["laatikko"], valittu)

def avaa_muokkauslomake():
    paikka = kirjoita_tiedot_lomakkeeseen()
    ik.nayta_ali_ikkuna(komponentit["levylomake"], "Muokkaa levyä")
    tila["toiminto"] = MUOKKAA
    tila["valittu"] = paikka

def kirjoita_tiedot_lomakkeeseen():
    valittu, sisalto = ik.lue_valittu_rivi(komponentit["laatikko"])
    levy = tila["kokoelma"][valittu]
    ik.kirjoita_tekstikenttaan(komponentit["lomake_artisti"], levy["artisti"])
    ik.kirjoita_tekstikenttaan(komponentit["lomake_albumi"], levy["albumi"])
    ik.kirjoita_tekstikenttaan(komponentit["lomake_kpl_n"], levy["kpl_n"])
    ik.kirjoita_tekstikenttaan(komponentit["lomake_kesto"], levy["kesto"])
    ik.kirjoita_tekstikenttaan(komponentit["lomake_vuosi"], levy["julkaisuvuosi"])
    return valittu

def jarjesta(kokoelma):
    """
    Järjestää parametrissa olevan kokoelma-listan. Pyytää käyttäjää valitsemaan
    kentän, jonka perusteella järjestäminen tehdään, sekä sen onko järjestys
    nouseva vai laskeva. Kokoelma järjestään "paikallaan", eli siitä ei luoda uutta
    kopiota.
    """

    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_albumi, reverse=kaanna)
    elif kentta == "3":
        kokoelma.sort(key=valitse_kpl_n, reverse=kaanna)
    elif kentta == "4":
        kokoelma.sort(key=valitse_kesto, reverse=kaanna)
    elif kentta == "5":
        kokoelma.sort(key=valitse_julkaisuvuosi, reverse=kaanna)
    else: 
        print("Kenttää ei ole olemassa")
  
def muotoile_rivi(levy, i):
    return "{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"]
    )

def tulosta(kokoelma):
    for i, levy in enumerate(kokoelma):
        ik.lisaa_rivi_laatikkoon(komponentit["laatikko"], muotoile_rivi(levy, i + 1))

def rakenna_kokoelma(kansio):
    try:
        tila["kokoelma"] = nuuskija.lue_kokoelma(kansio)
    except FileNotFoundError:
        print("Kansiota ei löytynyt")

def avaa_latausikkuna():
    polku = ik.avaa_tiedostoikkuna("Valitse kokoelmatiedosto (JSON)")
    lataa_kokoelma(polku)
    tulosta(tila["kokoelma"])

def avaa_rakennusikkuna():
    polku = ik.avaa_hakemistoikkuna("Valitse kokoelman juurikansio")
    rakenna_kokoelma(polku)
    tulosta(tila["kokoelma"])

def avaa_tallennusikkuna():
    polku = ik.avaa_tallennusikkuna("Valitse tallennettava tiedosto")
    tallenna_kokoelma(tila["kokoelma"], polku)

def avaa_lisayslomake():
    ik.nayta_ali_ikkuna(komponentit["levylomake"], "Lisää levy")
    tila["toiminto"] = LISAA

def tallenna_lomake():
    if tila["toiminto"] == LISAA:
        onnistui = lisaa(tila["kokoelma"])
        paikka = len(tila["kokoelma"]) - 1
    elif tila["toiminto"] == MUOKKAA:
        paikka = tila["valittu"]
        onnistui = muokkaa(tila["kokoelma"], paikka)
        if onnistui:
            ik.poista_rivi_laatikosta(komponentit["laatikko"], paikka)
            tila["valittu"] = None
    else:
        return

    if onnistui:
        ik.lisaa_rivi_laatikkoon(
            komponentit["laatikko"], muotoile_rivi(tila["kokoelma"][paikka]), paikka
        )
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_artisti"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_albumi"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_kpl_n"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_kesto"])
        ik.tyhjaa_kentan_sisalto(komponentit["lomake_vuosi"])
        ik.piilota_ali_ikkuna(komponentit["levylomake"])
        tila["toiminto"] = EI_VALITTU

def lopeta():
    ik.lopeta()

def luo_ikkuna():
    # Pääikkunan luonti
    ikkuna = ik.luo_ikkuna("Kokoelmaohjelma 0.1 alpha")
    nappikehys = ik.luo_kehys(ikkuna, ik.VASEN)
    kokoelmakehys = ik.luo_kehys(ikkuna, ik.VASEN)
    latausnappi = ik.luo_nappi(nappikehys, "Lataa", avaa_latausikkuna)
    rakennusnappi = ik.luo_nappi(nappikehys, "Rakenna", avaa_rakennusikkuna)
    tallennusnappi = ik.luo_nappi(nappikehys, "Tallenna", avaa_tallennusikkuna)
    ik.luo_vaakaerotin(nappikehys, 5)
    lisaysnappi = ik.luo_nappi(nappikehys, "Lisää", avaa_lisayslomake)
    poistonappi = ik.luo_nappi(nappikehys, "Poista", poista)
    muokkausnappi = ik.luo_nappi(nappikehys, "Muokkaa", avaa_muokkauslomake)
    ik.luo_vaakaerotin(nappikehys, 5)
    lopetusnappi = ik.luo_nappi(nappikehys, "Lopeta", lopeta)
    komponentit["laatikko"] = ik.luo_listalaatikko(kokoelmakehys)

    # Ali-ikkunan luonti
    levylomake = ik.luo_ali_ikkuna("Levyn tiedot")
    kenttakehys = ik.luo_kehys(levylomake, ik.YLA)
    nappikehys = ik.luo_kehys(levylomake, ik.YLA)
    ohjekehys = ik.luo_kehys(kenttakehys, ik.VASEN)
    syotekehys = ik.luo_kehys(kenttakehys, ik.VASEN)
    ik.luo_tekstirivi(ohjekehys, "Artisti")
    komponentit["lomake_artisti"] = ik.luo_tekstikentta(syotekehys)
    ik.luo_tekstirivi(ohjekehys, "Albumi")
    komponentit["lomake_albumi"] = ik.luo_tekstikentta(syotekehys)
    ik.luo_tekstirivi(ohjekehys, "Kpl N")
    komponentit["lomake_kpl_n"] = ik.luo_tekstikentta(syotekehys)
    ik.luo_tekstirivi(ohjekehys, "Kesto (HH:MM:SS)")
    komponentit["lomake_kesto"] = ik.luo_tekstikentta(syotekehys)
    ik.luo_tekstirivi(ohjekehys, "Julkaisuvuosi")
    komponentit["lomake_vuosi"] = ik.luo_tekstikentta(syotekehys)
    ik.luo_nappi(nappikehys, "Tallenna", tallenna_lomake)
    ik.piilota_ali_ikkuna(levylomake)
    komponentit["levylomake"] = levylomake
    ik.kaynnista()

if __name__ == "__main__":
    try:
        luo_ikkuna()
    except KeyboardInterrupt:
        print("Ohjelma keskeytettiin, kokoelmaa ei tallennettu")

?
  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ää globaalin tilan ylikansoitusta, 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
Purkamiseksi (eng. unpacking) kutsutaan sitä, kun sarjatyyppinen arvo tallennetaan useaan muuttujaan kerralla. Yleisin esimerkki purkamisesta on paluuarvojen tallentaminen useaan muuttujaan, kun funktio palauttaa useita arvoja kerralla. Purkamista voidaan myös käyttää suoraan listojen ym. paloitteluun muuttujiksi. Purkamista voi käyttää vain silloin, kun tiedetään, että purettavat arvot sisältävät aina saman, ennalta tunnetun määrän alkioita.
  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 yleisimmin näitä kohdataan f-merkkijonoina.
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.