Python-opas

Tämä opas käsittelee Python-kielen perusasioita tämän kurssin näkökulmasta. Oletuksena on, että osaat ohjelmoida ennestään jollakin ohjelmointikielellä.

Perusteiden oppimisen jälkeen hyvä lähde on Pythonin dokumentaatio.

Pythonin asennus

Python on valmiiksi asennettuna useissa järjestelmissä. Tarvittaessa löydät ohjeita asentamiseen Pythonin lataussivulta.

Nykyään käytettävä Pythonin versio on Python 3. Kaikki kurssin esimerkit olettavat, että käytössäsi on tämä Pythonin versio.

Pythonin käyttäminen

Komentotulkki

Pythonin komentotulkki on kätevä tapa kielen ominaisuuksien testaamiseen. Komentotulkki käynnistyy komennolla python3, minkä jälkeen voi kirjoittaa suoritettavia komentoja.

$ python3
>>> 1 + 2
3
>>> len("testi")
5
>>> quit()

Koodi tiedostossa

Seuraavassa tiedostossa test.py on Python-koodi, joka kysyy käyttäjän nimeä ja näyttää sitten tervehdyksen:

test.py

# kommentti merkitään näin
name = input("Anna nimi: ")
print("Moikka,", name)

Koodi suoritetaan näin komentoriviltä:

$ python3 test.py
Anna nimi: Kotivalo
Moikka, Kotivalo

Tyypit ja muuttujat

Pythonin tavallisimmat tietotyypit ovat int (kokonaisluku), float (liukuluku), str (merkkijono) ja bool (totuusarvo). Esimerkkejä operaatioista:

print(5 * (2 + 4)) # 30
print(5 / 2) # 2.5
print(5 // 2) # 2
print(3 ** 4) # 81
print(2 ** 100) # 1267650600228229401496703205376
print("esi" + "merkki") # esimerkki
print("abc" * 4) # abcabcabcabc
print(1 + 2 == 3) # True
print(3 > 7) # False

Arvo None tarkoittaa puuttuvaa tietoa.

Pythonissa uusi muuttuja syntyy automaattisesti, kun muuttujalle annetaan arvo:

name = "Maija"
age = 25

Muuttujalla ei ole kiinteää tyyppiä vaan tyyppi määräytyy sen mukaan, millainen arvo muuttujaan sijoitetaan.

Python on tarkka tyypeistä, eikä esimerkiksi seuraava koodi toimi, koska merkkijonoa ja lukua ei voi suoraan yhdistää keskenään:

a = "testi"
b = 123
c = a + b

Ratkaisu on käyttää funktiota str, joka muuttaa tyypin merkkijonoksi:

a = "testi"
b = 123
c = a + str(b)

Vastaavasti funktiot int ja float muuttavat tyypin kokonais- ja liukuluvuksi.

Lohkot

Pythonissa sisennys ilmaisee, mikä koodi kuuluu lohkon sisään esimerkiksi ehto- ja toistorakenteissa.

Esimerkiksi seuraavassa koodissa on if-rakenne:

if status == 1:
    role = "user"
elif status == 2:
    role = "admin"
else:
    role = "guest"

Seuraavassa koodissa puolestaan on while-rakenne:

counter = 10
while counter >= 1:
    print(counter)
    counter -= 1

Listat

Pythonin perustietorakenne on lista, jonka alkiot merkitään hakasulkujen [ ja ] sisään. Esimerkiksi seuraava koodi luo listan, jossa on kolme sanaa:

words = ["apina", "banaani", "cembalo"]

Toinen tapa luoda lista on aloittaa tyhjästä listasta ja lisätä alkiot append-metodilla:

words = []
words.append("apina")
words.append("banaani")
words.append("cembalo")

Listan pituus saadaa funktiolla len ja listan alkoihin pääsee käsiksi []-syntaksilla:

print(len(words)) # 3
print(words[0]) # apina
print(words[1]) # banaani
words[0] = "apila"
print(words[0]) # apila

Pythonissa voi myös indeksoida negatiivisilla luvuilla, jolloin alkio haetaan listan lopusta laskien:

print(words[-1]) # cembalo

Operaattori in kertoo, onko tietty alkio listalla:

print("cembalo" in words) # True
print("tuuba" in words) # False

Lista ja merkkijono muistuttavat Pythonissa toisiaan, ja merkkijonon merkkejä pystyy käsittelemään samaan tapaan kuin listan alkioita. Erona on kuitenkin, että merkkijonon sisältöä ei voi muuttaa eli merkkijonossa ei ole esimerkiksi metodia append.

For-silmukka

Pythonin for-silmukka käy läpi listan alkiot:

words = ["apina", "banaani", "cembalo"]
for word in words:
    print(word)
apina
banaani
cembalo

Perinteisempi for-silmukka saadaan aikaan funktion range avulla. Tämä funktio tuottaa lukuvälin, joka voidaan käydä läpi silmukalla.

for i in range(5):
    print("rivi", i)
rivi 0
rivi 1
rivi 2
rivi 3
rivi 4

Tässä range(n) tarkoittaa, että lukuväli alkaa 0:sta ja päättyy juuri ennen lukua n. Vastaavasti range(a, b) tarkoittaa, että lukuväli alkaa a:sta ja päättyy juuri ennen lukua b.

Lisää tietorakenteita

Sanakirja

Sanakirja (dict) muodostuu avain-arvo-pareista. Esimerkiksi seuraava koodi luo sanakirjan, jossa on kolme paria:

ages = {"Maija":25, "Anna":20, "Kaaleppi":42}

Voimme myös luoda vastaavan sanakirjan näin:

ages = {}
ages["Maija"] = 25
ages["Anna"] = 20
ages["Kaaleppi"] = 42

Sanakirjasta voi hakea tietoa avaimen perusteella:

print(ages["Anna"]) # 20

Operaattori in kertoo, onko sanakirjassa tiettyä avainta:

print("Maija" in ages) # True
print("Uolevi" in ages) # False

Voimme käydä sanakirjan avaimet läpi for-silmukalla:

for name in ages:
    print(name, "on", ages[name], "vuotta")
Maija on 25 vuotta
Anna on 20 vuotta
Kaaleppi on 42 vuotta

Tuple

Tuple on kokoelma arvoja sulkujen sisällä. Se näyttää melko samalta kuin lista:

person = ("Maija", 25, "Finland")
print(person[0]) # Maija
print(person[1]) # 25
print(person[2]) # Finland

Tuple eroaa kuitenkin listasta siinä, että sen sisältöä ei voi muuttaa. Tuplea käytetään toisiinsa liittyvän tiedon kokoamiseen yhteen yllä olevan esimerkin kaltaisesti.

Tosi vs. epätosi

Pythonissa mitä tahansa arvoa voidaan käyttää vertailussa totuusarvon tapaan. Epätosia arvoja ovat arvon False lisäksi erilaiset tyhjät ja olemattomat arvot, kuten None, 0, [] (tyhjä lista), {} (tyhjä sanakirja) ja () (tyhjä tuple).

Tätä ominaisuutta voi hyödyntää usein vertailuissa. Tarkastellaan esimerkkinä seuraavaa koodia:

if len(words) > 0:
    print("There are", len(words), "words")
else:
    print("There are no words")

Koska tyhjä lista vastaa arvoa False ja mikä tahansa muu lista vastaa arvoa True, voimme kirjoittaa ehdon lyhemmin näin:

if words:
    print("There are", len(words), "words")
else:
    print("There are no words")

Viittaus ja kopiointi

Pythonissa muuttujassa on aina viittaus varsinaiseen sisältöön. Seuraava koodi havainnollistaa asiaa:

lista1 = [1, 2, 3]
lista2 = lista1
lista1[0] = 5
print(lista1[0]) # 5
print(lista2[0]) # 5

Koodissa muuttujat lista1 ja lista2 viittaavat samaan listaan, joten kun listaa muutetaan muuttujan lista1 kautta, niin muutos heijastuu myös muuttujaan lista2.

Voimme kuitenkin tarvittaessa luoda listasta kopion [:]-syntaksilla, jolloin listat ovat erillisiä:

lista1 = [1, 2, 3]
lista2 = lista1[:]
lista1[0] = 5
print(lista1[0]) # 5
print(lista2[0]) # 1

Funktiot

Funktion määrittely

Oma funktio määritellään avainsanan def avulla. Esimerkiksi seuraava koodi määrittelee funktion hello, joka tervehtii parametrina annettua nimeä:

def hello(name):
    print("Moikka,", name)

hello("Liisa")
hello("Kaaleppi")
Moikka, Liisa
Moikka, Kaaleppi

Seuraava funktio check puolestaan tarkastaa, että nimen pituus on enintään maksimipituus:

def check(name, max_length):
    return len(name) <= max_length

print(check("Liisa", 6)) # True
print(check("Kaaleppi", 3)) # False

Muuttujien näkyvyys

Päätasolla luotu muuttuja näkyy kaikissa funktioissa:

def test():
    print(x) # 5

x = 5
test()
print(x) # 5

Jos taas muuttuja luodaan funktion sisällä, se näkyy vain kyseisessä funktiossa:

def test():
    x = 5
    print(x) # 5

test()
print(x) # ei toimi

Jos muuttuja saa arvon sekä päätasolla että funktiossa, syntyy kaksi erillistä muuttujaa:

def test():
    x = 2
    print(x) # 2

x = 1
test()
print(x) # 1

Virheenkäsittely

Koodissa mahdollisesti tapahtuvan virheen voi käsitellä try/except-rakenteella.

Esimerkiksi seuraava funktio pyrkii lukemaan käyttäjältä kokonaisluvun. Jos käyttäjä antaa jotain muuta, funktion int-kutsuminen aiheuttaa virheen, jolloin virheen käsittelyn seurauksena funktio palauttaa arvon 0.

def read_int():
    value = input("Anna luku: ")
    try:
        result = int(value)
    except:
        result = 0
    return result

Moduulit

Valmiit moduulit

Komento import ottaa käyttöön moduulin. Esimerkiksi Pythonin standardikirjastossa on suuri määrä moduuleita eri tarkoituksiin.

Seuraava koodi käyttää Pythonin standardikirjaston moduulia random, jossa on satunnaisuuteen liittyviä toimintoja. Koodi arpoo satunnaisen luvun funktiolla randint.

import random
print(random.randint(1, 10))

Toinen tapa on hakea moduulista funktio, jolloin sitä voi käyttää suoraan:

from random import randint
print(randint(1, 10))

Käytämme kurssilla myös Pythonin standardikirjaston ulkopuolisia moduuleja kuten Flask-kirjaston moduulia flask.

Omat moduulit

Kun tiedostossa on Python-koodia, tiedostoa voidaan käyttää moduulina. Esimerkiksi seuraava tiedosto test.py määrittelee moduulin test:

test.py

def hello(name):
    print("Moikka,", name)

Tämän jälkeen voimme käyttää moduulia näin:

import test
test.hello("Maija")
test.hello("Anna")
test.hello("Uolevi")
Moikka, Maija
Moikka, Anna
Moikka, Uolevi

Moduulin suoritus

Kun moduuli otetaan mukaan import-komennolla, siellä oleva koodi suoritetaan. Kuitenkin jos moduuli otetaan mukaan useita kertoja, koodi suoritetaan vain ensimmäisellä kerralla.

Seuraava moduuli havainnollistaa asiaa:

test.py

def hello(name):
    print("Moikka,", name)

print("Täällä ollaan")

Seuraava koodi ottaa moduulin mukaan kahdesti, mutta vain ensimmäisellä kerralla suoritetaan moduulissa oleva print-komento:

import test
test.hello("Maija")
test.hello("Anna")
import test
test.hello("Uolevi")
Täällä ollaan
Moikka, Maija
Moikka, Anna
Moikka, Uolevi

Lisäaiheita

Merkkijonon muotoilu

Melko uusi Pythonin ominaisuus on f-string, jossa merkkijonon alussa on merkki f. Tämän avulla merkkijonon sisällä voi käyttää muuttujia ja muita lausekkeita aaltosuluissa.

name = "Maija"
age = 25
print(f"{name} on {age}-vuotias") # Maija on 25-vuotias

Listakooste

Listakooste luo uuden listan vanhan listan perusteella ja voi samalla muokata alkioita jollakin tavalla. Esimerkiksi seuraava koodi luo uuden listan, jossa on jokaisen sanan pituus:

words = ["apina", "banaani", "cembalo"]
lengths = [len(x) for x in words]
print(lengths) # [5, 6, 6]

Säännölliset lausekkeet

Säännöllinen lauseke (regex) kuvailee, mikä on haluttu merkkijonon muoto. Voimme käsitellä säännöllisiä lausekkeita moduulin re avulla.

Esimerkiksi seuraava koodi varmistaa, että merkkijono word muodostuu kirjaimista az:

import re

word = "apina"
if re.match(r"^[a-z]+$", word):
    ok = True

Tässä tapauksessa säännöllinen lauseke on ^[a-z]+$. Se muodostuu seuraavista osista:

Dekoraattorit

Dekoraattori luo funktion ympärille kuoren, jonka avulla funktion kutsuminen aiheuttaa automaattisesti jonkin lisätoiminnon.

Esimerkiksi seuraavassa koodissa dekoraattori debug tulostaa rivin tietoa aina, kun funktiota kutsutaan, ja näyttää funktion nimen ja parametrit.

import functools

def debug(f):
    @functools.wraps(f)
    def wrapper(*args):
        print(f"kutsu {f.__name__} parametreilla {args}")
        f(*args)
    return wrapper

@debug
def hello(name):
    print("Moikka,", name)

hello("Maija")
hello("Kaaleppi")
kutsu hello parametreilla ('Maija',)
Moikka, Maija
kutsu hello parametreilla ('Kaaleppi',)
Moikka, Kaaleppi

Flask-kirjastossa dekoraattorit ovat keskeisessä roolissa, koska niiden avulla määritetään, mitä sivupyyntöjä mikäkin funktio käsittelee.