Arvutiteaduse instituut
  1. Kursused
  2. 2017/18 kevad
  3. Programmeerimise alused II (LTAT.TK.001)
EN
Logi sisse

Programmeerimise alused II 2017/18 kevad

  • Kursuse info
  • 1. Kahemõõtmeline järjend
  • 2. Kahekordne tsükkel
  • 3. Andmestruktuurid
  • 4. Viitamine ja muteerimine

4.1 Viitamine 4.2 Muteerimine 4.3 Järjendi muteerimine 4.4 Funktsioon ja muteerimine 4.5 Kordamine 4.6 Silmaring: Objekt-orienteeritud programmeerimine

  • 5. Testimine ja silumine. Rekursioon
  • 6. Rekursioon II
  • Korraldajad
IV OSA sisukord

4.5 OBJEKT-ORIENTEERITUD PROGRAMMEERIMINE

Klassid kui tabelid

Eelmisel nädalal vaatasime, kuidas andmeid hoitakse andmebaasides ning kuidas neid andmeid andmebaasist kätte saada. Sellel nädalal vaatame, kuidas andmeid saab hoida objektides.

Objektis informatsiooni hoidmiseks peame läbi mõtlema, kuidas soovime objektis andmeid kirjeldada. Sarnaste objektide jaoks ühiste reeglite sätestamiseks kasutame klasse. Klassid on nagu andmebaaside tabelid, mis ütlevad, millist infot me iga tabelis oleva isendi kohta teame. Klassi defineerimiseks kasutatakse märksõna class.

Meenutame Õppija tabelit: igal Õppijal on enda matriklinumber, eesnimi, perekonnanimi ja isikukood. Need neli tunnust võime lugeda muutujateks, mida väärtustame iga Õppija jaoks eraldi.

Muutujaid, mis kehtivad iga isendi enda kohta, nimetatakse isendimuutujateks ehk isendiväljadeks. Pythonis kasutatakse nende klassisiseseks eristamiseks märksõna self.

Nõnda saame klassis Õppija defineerida muutujad self.matrikli_nr, self.eesnimi, self.perenimi ja self.isikukood. Klassist väljaspool nende muutujate kasutamisel kasutatakse self märksõna asemel vastavat isendit hoidva muutuja nime. self märksõna kasutatakse ka isendi informatsiooni kasutavate klassis defineeritud funktsioonide esimese argumendina. Ühte levinud isendispetsiifilist funktsiooni vaatleme järgmisena.

Uue isendi loomine

Uue isendi loomisel soovime need isendimuutujad väärtustada ehk omistada neile mingid väärtused. Selleks kasutatakse konstruktorit, mis on klassile iseloomulik funktsioon. Konstruktorit kasutatakse iga isendi loomisel isendimuutujate väärtustamiseks. Funktsiooni nimeks on __init__, mis tuleneb uue isendi initsialiseerimisest ehk lähtestamisest. Funktsiooni parameetriteks on esmalt märksõna self ning seejärel kõik teised muutujad, mida soovime isendisse salvestada.

class Õppija:
    def __init__(self, mat_nr, eesnimi, perenimi, isikukood):
        self.matrikli_nr = mat_nr
        self.eesnimi = eesnimi
        self.perenimi = perenimi
        self.isikukood = isikukood

Märkame, et self.eesnimi muutuja on isendispetsiifiline, kuid eesnimi muutuja pärineb funktsiooni parameetritest. Kui kasutada sama nimega muutujaid, tuleb olla eriti tähelepanelik, millist muutujat me igal hetkel kasutame. Kui kogemata muutujad segamini ajame, võib meie loodav programm käituda ettearvamatult. Loodud konstruktorit saame kasutada uue isendi loomisel. Kui konstruktori __init__ defineerimine oli nagu andmebaaside CREATE TABLE käsk, siis konstruktori kasutamine on analoogne INSERT INTO käsuga:

õppur1 = Õppija("A034", "Albert", "Paas", 34105212737)
õppur2 = Õppija("A037", "Pearu", "Murakas", 34206122154)
print(õppur1.eesnimi)
print(õppur2.eesnimi)

Sarnaselt üksikute muutujate lugemisele võime isendimuutujaid ka ümber väärtustada või lisada.

õppur1.lemmikloom = "koer"
print(õppur1.lemmikloom)

Väljastatakse "koer".

Isendispetsiifilised funktsioonid

Kui soovime välja printida informatsiooni isendi kohta, siis üheks variandiks on üksikute isendiväljade kasutamine. print(õppur1) annab aga hetkel eriskummalise tulemuse <__main__.Õppija object at 0x02BFBE90> , mis ütleb, et tegu on isendiga klassist Õppija ning see asub mäluväljal 0x02BFBE90. Selleks, et print käsk annaks meile informatiivsema kirjelduse, tuleb klassis defineerida isendispetsiifiline funktsioon __str__:

def __str__(self):
    return "Õppija nimi: "+self.eesnimi+" "+self.perenimi+"."

Kui soovime, võime isendispetsiifilisi funktsioone juurde teha. Sellisel juhul võime sama funktsiooni välja kutsuda mistahes Õppija isendi peal, saades isendi andmetest sõltuva tulemuse.

def sugu(self):
    if self.isikukood//10000000000%2 == 1: #Vaatleme, kas isikukoodi esimene number on paaris- või paaritu arv.
        return "M"
    else:
        return "N"

Funktsioonide väljakutsumine on sarnane sõnede peal split ja strip funktsioonide kasutusega:

print(õppur1.sugu())

Staatilised muutujad ja funktsioonid

Lisaks isendispetsiifilistele muutujatele ja funktsioonidele võib klassis defineerida ka kõikidele sama klassi isenditele ühiseid muutujaid ja funktsioone. Neid nimetatakse staatilisteks, kuna nad ei muutu sõltuvalt isendist. Staatilisi muutujaid võib võrrelda globaalsete muutujatega, mispuhul isendispetsiifilised muutujad on sarnased lokaalsete muutujatega - kasutatakse funktsioonides.

Sarnaselt globaalsete muutujatega deklareeritakse staatilised muutujad klassi sees funktsiooniväliselt. Erinevalt isendispetsiifiliste muutujatest tuleb staatiliste muutujate lugemiseks või muutmiseks pöörduda isendi asemel terve klassi poole. Kui meie näites oleks eesnimi staatiline muutuja, tuleks õppur1.eesnimi asemel kasutada Õppija.eesnimi. Seejuures saab, kuid ei ole soovitatav, kasutada sama nimega staatilisi ja isendispetsiifilisi muutujaid.

Staatilised funktsioonid erinevad isendispetsiifilistest vaid paari omaduse poolest: parameetrites ei kasutata märksõna self, funktsioonis sees ei saa mittestaatilisi isendimuutujaid kasutada ning funktsiooni väljakutsumiseks kasutatakse isendi muutujanime asemel klassi üldnimetust. Võime lisada klassi algusesse ühe muutuja kool, ühe staatilise funktsiooni ning muuta väljaprinditavat infot:

class Õppija:
    kool = "Tartu Ülikool"
    def kusÕpib():
        return "Õpib koolis "+Õppija.kool+"."
    def __str__(self):
        return "Õppija nimi: "+self.eesnimi+" "+self.perenimi+".\n"+Õppija.kusÕpib()

Nüüd on huvitav uurida print(õppur1) ja print(õppur2) väljundit.

Lõpetuseks

Oleme vaadelnud, kuidas ehitada objekt erinevate omadustega. Objekte on hea kasutada olukordades, kus ühe ja sama väärtusega on seotud hästi palju teisi. Õppija klassi asemel oleksime saanud kasutada ka näiteks kolme sõnastikku, kus ühes on matriklinumbrile vastav eesnimi, teises perekonnanimi, kolmandas isikukood. Ühendades kõik ühte isendisse muutub kood palju kergemini loetavaks ja hallatavamaks. Tähele võib panna ka võimalust panna isendeid teistesse andmestruktuuridesse nagu järjend, mispuhul ei ole vaja iga uue isendi jaoks uut muutujanime, piisab järjendi nimest ja indeksist. Sellisel juhul saab isendeid tekitada tsüklitega.

Näidiskoodi lõppkuju:

class Õppija:
    kool = "Tartu Ülikool"
    def kusÕpib():
        return "Õpib koolis "+Õppija.kool+"."
    def __init__(self, mat_nr, eesnimi, perenimi, isikukood):
        self.matrikli_nr = mat_nr
        self.eesnimi = eesnimi
        self.perenimi = perenimi
        self.isikukood = isikukood
    def __str__(self):
        return "Õppija nimi: "+self.eesnimi+" "+self.perenimi+".\n"+Õppija.kusÕpib()
    def arvuta(a,b):
        return a+b
    def sugu(self):
        if self.isikukood//10000000000%2 == 1:
            return "M"
        else:
            return "N"
#Konstruktori kasutus
õppur1 = Õppija("A034", "Albert", "Paas", 34105212737)
õppur2 = Õppija("A037", "Pearu", "Murakas", 34206122154)

#Isendimuutuja tekitamine/muutmine
õppur1.lemmikloom = "koer"
print(õppur1.lemmikloom)

#Isendispetsiifiline funktsioon
print(õppur1.sugu())

#Väljastamine, kasutades isendispetsiifilist funktsiooni koos staatilise muutuja ja funktsiooniga
print(õppur1)
print(õppur2)

#Muu staatilise funktsiooni kasutus
print(Õppija.arvuta(1,2))


IV OSA sisukord
  • Arvutiteaduse instituut
  • Loodus- ja täppisteaduste valdkond
  • Tartu Ülikool
Tehniliste probleemide või küsimuste korral kirjuta:

Kursuse sisu ja korralduslike küsimustega pöörduge kursuse korraldajate poole.
Õppematerjalide varalised autoriõigused kuuluvad Tartu Ülikoolile. Õppematerjalide kasutamine on lubatud autoriõiguse seaduses ettenähtud teose vaba kasutamise eesmärkidel ja tingimustel. Õppematerjalide kasutamisel on kasutaja kohustatud viitama õppematerjalide autorile.
Õppematerjalide kasutamine muudel eesmärkidel on lubatud ainult Tartu Ülikooli eelneval kirjalikul nõusolekul.
Tartu Ülikooli arvutiteaduse instituudi kursuste läbiviimist toetavad järgmised programmid:
euroopa sotsiaalfondi logo