Python-oppimateriaali (CHEM-A2600)

Olio-ohjelmointi

Aiemmin tällä kurssilla olemme tutustuneet erilaisiin tietorakenteisiin kuten listat, sanakirjat ja NumPy-taulukot. Olemme myös tutustuneet funktioihin, joilla näitä tietorakenteita voi käsitellä. Esimerkkinä vaikkapa max(lista), joka palauttaa listan suurimman alkion.

Tutustutaan nyt lyhyesti olioihin (engl. object). Voimme ajatella olioita tietorakenteina, jotka sisältävät myös tietojen käsittelyyn tarkoitettuja funktioita.

Luokan määritteleminen ja olioiden luominen

Jotta voimme luoda uuden olion, meidän pitää ensin määritellä luokka (engl. class) joka kuvaa olion ominaisuudet. Määritellään luokka Molekyyli (luokkien nimet kirjoitetaan isolla alkukirjaimella):

class Molekyyli:
    def __init__(self, kaava, moolimassa):
        self.kaava = kaava
        self.moolimassa = moolimassa
       
    def laske_ainemaara(self, massa):
        return massa / self.moolimassa

Molekyyli-luokka sisältää kaksi funktiomäärittelyä. Näitä luokan sisältämiä funktioita kutsutaan metodeiksi (engl. method) erotuksena tavallisista funktioista, jotka eivät kuulu mihinkään luokkaan. 

Molekyyli-luokka sisältää käynnistysmetodin __init__ ja metodin laske_ainemaara. Huomaa, että molempien metodien ensimmäinen parametri on self. Tämä parametri viittaa aina olioon itseensä. Python hoitaa self-parametrin automaattisesti, eli sitä ei anneta, kun metodia kutsutaan.

Käynnistysmetodissa __init__ luodaan oliolle kaksi kenttää: kaava ja moolimassa. Kenttiin pitää viitata metodin self-parametrin avulla.

Katsotaan, mitä määrittelemällämme luokalla voidaan nyt tehdä. Luodaan Molekyyli-luokkaan pohjautuvat oliot metaani ja etaani:

metaani = Molekyyli("CH4", 16.04) 
etaani = Molekyyli("C2H6", 30.07)

Käsky Molekyyli("CH4", 16.04) tarkoittaa, että Molekyyli-luokan __init__-metodia kutsutaan parametreilla "CH4" ja 16.04 (self-parametria ei anneta, vaan Python antaa sen __init__-käynnistysmetodille automaattisesti). Käsky palauttaa uuden olion, jonka kentät kaava ja moolimassa on täytetty arvoilla "CH4" ja 16.04. Tämä olio sijoitetaan muuttujaan metaani.

Kokonainen olioesimerkki

Luokkamäärittelyn pohjalta voi luoda mielivaltaisen määrän uusia olioita. Katsotaan kokonaisen esimerkin avulla, miten olioiden kenttiä voi lukea ja miten niiden metodeja käytetään:

class Molekyyli:
    def __init__(self, kaava, moolimassa):
        self.kaava = kaava
        self.moolimassa = moolimassa
       
    def laske_ainemaara(self, massa):
        return massa / self.moolimassa

metaani = Molekyyli("CH4", 16.04) 
etaani = Molekyyli("C2H6", 30.07)

# Käytetään olioiden kenttiä
print(f"Metaanin molekyylikaava on {metaani.kaava}")
print(f"Etaanin molekyylikaava on {etaani.kaava}")
print(f"Metaanin moolimassa on {metaani.moolimassa} g/mol")
print(f"Etaanin moolimassa on {etaani.moolimassa} g/mol")

# Käytetään laske_ainemaara-metodia. 
# Huomaa, että self-parametria ei anneta
n_metaani = metaani.laske_ainemaara(5.0) # 5 g metaania
n_etaani = etaani.laske_ainemaara(7.0)   # 7 g etaania
print(f"5 g metaania on {n_metaani:.3f} mol")
print(f"7 g etaania on {n_etaani:.3f} mol")

tulostaa

Metaanin molekyylikaava on CH4
Etaanin molekyylikaava on C2H6
Metaanin moolimassa on 16.04 g/mol
Etaanin moolimassa on 30.07 g/mol
5 g metaania on 0.312 mol
7 g etaania on 0.233 mol

Huomaa, miten laske_ainemaara-metodissa self.moolimassa viittaa kunkin olion omaan moolimassa-kenttään. Sillä on siis eri arvo metaanille ja etaanille. Näin ainemäärä lasketaan oikein kullekin oliolle. Parametri massa taas määritetään aina metodia laske_ainemaara kutsuttaessa.

Kannattaa tutustua esimerkkiin huolella. Esimerkki on yksinkertainen, mutta sen tarkoituksena on havainnollistaa, miten olioiden avulla voidaan yhdistää tietorakenteet ja funktiot samaan pakettiin. self-parametrin käyttö on yksi olio-ohjelmoinnin avainkäsitteistä.

Yllättävä käänne

Olemme itse asiassa käyttäneet olioita aivan koko kurssin ajan! Pythonissa oikeastaan kaikki asiat ovat olioita. Esimerkiksi int ja float -tyyppiset muuttujat tai list ja dict -tietorakenteet ovat kaikki olioita, jotka sisältävät myös metodeja kyseisten olioiden käsittelemiseksi:

# float-olio sisältää esimerkiksi is_integer()-metodin
liukuluku = 3.14
print(liukuluku.is_integer())
liukuluku_int = 3.0
print(liukuluku_int.is_integer())

tulostaa

False
True

list-tietorakenne sisältää useita metodeja, joita olemmekin jo käyttäneet

lista = [1, 2, 3]
# Tulostetaan ykkösten määrä listassa
print(lista.count(1))
# Lisätään yksi ykkönen listaan
lista.append(1)
# Tulostetaan ykkösten määrä listassa
print(lista.count(1))

tulostaa

1
2

Tehtävä 6.6.1