13. OBJEKTORIENTEERITUD PROGRAMMEERIMINE
Sissejuhatus
Selles peatükis vaatame, kuidas andmeid saab hoida objektides. Vaatame, kuidas luua klasse, lisada sinna meetodeid ehk isendispetsiifilisi funktsioone, milleks on vaja konstruktorit ja kuidas kõike seda kasutada.
Objektis informatsiooni hoidmiseks peame läbi mõtlema, kuidas soovime objektis andmeid kirjeldada. Sarnaste objektide jaoks ühiste reeglite sätestamiseks kasutame klasse. Klassid ütlevad, millist infot me isendite kohta teame. Klassi defineerimiseks kasutatakse märksõna class
. Sellele märksõnale järgneb klassi nimi ja koolon. Klasside nimed kirjutatakse suure algustähega ja peavad olema unikaalsed. Klassi sisu kirjutatakse taandega.
class Õppija: # klassi sisu
Muutujaid, mis kehtivad iga isendi enda kohta, nimetatakse isendimuutujateks ehk isendiväljadeks.
Pythonis kasutatakse nende klassisiseseks eristamiseks märksõna self
. Isendivälju saame kasutada selle märksõna kaudu.
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 meetodite esimese argumendina. Nii võime öelda, et märksõna self
on alati konstruktori ja meetodite argumentide hulgas esimene. Nüüd aga vaatame, kuidas luua konstruktorit ja meetodeid.
Konstruktor
Konstruktor on klassile iseloomulik meetod, kus defineeritakse isendimuutujad. Konstruktorit kasutatakse iga isendi loomisel isendimuutujate väärtustamiseks. Meetodi nimeks on __init__
, mis tuleneb uue isendi initsialiseerimisest ehk lähtestamisest. Meetodi parameetriteks on esmalt märksõna self
ning seejärel kõik teised muutujad, mida soovime isendisse salvestada. Konstruktori sees omistatakse need väärtused vastavatele isendimuutujatele ehk isendiväljadele. Argumendi ja isendimuutuja nimi ei pea olema sama, aga võib olla.
class Õppija: def __init__(self, matrikli_nr, eesnimi, perenimi, isikukood): self.matrikli_nr = matrikli_nr self.eesnimi = eesnimi self.perenimi = perenimi self.isikukood = isikukood
Isendite loomine
Uue isendi loomisel soovime isendimuutujad väärtustada ehk omistada neile mingid väärtused. Saame seda teha vastavalt sellele, millised isendimuutujad konstruktoris on. Meie näites on nendeks matrikli_nr, eesnimi, perenimi, isikukood.
õppur1 = Õppija("A034", "Albert", "Paas", 34105212737) õppur2 = Õppija("A037", "Pearu", "Murakas", 34206122154) print(õppur1.eesnimi)
Albert
print(õppur2.eesnimi)
Pearu
Sarnaselt üksikute muutujate lugemisele võime isendimuutujaid ka ümber väärtustada või lisada.
õppur1.lemmikloom = "koer" print(õppur1.lemmikloom)
Väljastatakse "koer"
.
Meetodid
Klassis saame luua meetodeid, mis määravad objekti käitumise. Nii võime sama meetodi välja kutsuda mistahes Õppija
isendi peal, saades isendi andmetest sõltuva tulemuse.
class Õppija: def __init__(self, matrikli_nr, eesnimi, perenimi, isikukood): self.matrikli_nr = matrikli_nr self.eesnimi = eesnimi self.perenimi = perenimi self.isikukood = isikukood def sugu(self): ik = str(self.isikukood) if int(ik[0]) % 2 == 1: # Kontrollib, kas isikukoodi 1. number on paaritu arv. return "M" else: return "N"
Meetodite väljakutsumine on sarnane sõnede peal split
ja strip
meetodite kasutusega:
print(õppur1.sugu())
M
Meetod __str__
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 meetod __str__
:
class Õppija: def __init__(self, matrikli_nr, eesnimi, perenimi, isikukood): self.matrikli_nr = matrikli_nr self.eesnimi = eesnimi self.perenimi = perenimi self.isikukood = isikukood def sugu(self): ik = str(self.isikukood) if int(ik[0]) % 2 == 1: # Kontrollib, kas isikukoodi 1. number on paaritu arv. return "M" else: return "N" def __str__(self): return "Õppija nimi: " + self.eesnimi + " " + self.perenimi
print(õppur1)
Õppija nimi: Albert Paas
Veel muutujate defineerimisest
Klassis võib defineerida ka kõikidele sama klassi isenditele ühiseid muutujaid. Lisame meie näite konstruktorisse muutuja ülikool
ja anname väärtuseks "Tartu Ülikool"
:
class Õppija: def __init__(self, matrikli_nr, eesnimi, perenimi, isikukood): self.matrikli_nr = matrikli_nr self.eesnimi = eesnimi self.perenimi = perenimi self.isikukood = isikukood self.ülikool = "Tartu Ülikool" def sugu(self): ik = str(self.isikukood) if int(ik[0]) % 2 == 1: # Kontrollib, kas isikukoodi 1. number on paaritu arv. return "M" else: return "N" def __str__(self): return "Õppija nimi: " + self.eesnimi + " " + self.perenimi
Loendamine
Me saame kasutada meetodeid ka selleks, et midagi loendada või arvulist suurust muuta. Meie näites võiksime iga kord, kui üliõpilane läbib aine, suurendada läbitud ainete muutuja väärtust ühe võrra. Selleks lisame muutuja läbitud_ainete_arv
algväärtusega 0 ning loome meetodi läbi_aine
, mis suurendab muutuja läbitud_ainete_arv
väärtust ühe võrra.
class Õppija: def __init__(self, matrikli_nr, eesnimi, perenimi, isikukood): self.matrikli_nr = matrikli_nr self.eesnimi = eesnimi self.perenimi = perenimi self.isikukood = isikukood self.ülikool = "Tartu Ülikool" self.läbitud_ainete_arv = 0 def sugu(self): ik = str(self.isikukood) if int(ik[0]) % 2 == 1: # Kontrollib, kas isikukoodi 1. number on paaritu arv. return "M" else: return "N" def läbi_aine(self): self.läbitud_ainete_arv += 1 def __str__(self): return "Õppija nimi: " + self.eesnimi + " " + self.perenimi
Nüüd rakendame meetodit läbi_aine
näiteks isendiga õppur1
kaks korda ja kui väljastame tema läbitud ainete arvu, saame 2.
õppur1.läbi_aine() õppur1.läbi_aine() print(õppur1.läbitud_ainete_arv)
2
Isendid andmestruktuurides
Tähele võib panna ka võimalust panna isendeid teistesse andmestruktuuridesse nagu järjend.
õppurid = [õppur1, õppur2] for el in õppurid: print(el.eesnimi, el.perenimi + ", isikukood:", el.isikukood)
Albert Paas, isikukood: 34105212737 Pearu Murakas, isikukood: 34206122154
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.
Näidiskoodi lõppkuju:
class Õppija: def __init__(self, matrikli_nr, eesnimi, perenimi, isikukood): self.matrikli_nr = matrikli_nr self.eesnimi = eesnimi self.perenimi = perenimi self.isikukood = isikukood self.ülikool = "Tartu Ülikool" self.läbitud_ainete_arv = 0 def sugu(self): ik = str(self.isikukood) if int(ik[0]) % 2 == 1: # Kontrollib, kas isikukoodi 1. number on paaritu arv. return "M" else: return "N" def läbi_aine(self): self.läbitud_ainete_arv += 1 def __str__(self): return "Õppija nimi: " + self.eesnimi + " " + self.perenimi # Isendite loomine õppur1 = Õppija("A034", "Albert", "Paas", 34105212737) õppur2 = Õppija("A037", "Pearu", "Murakas", 34206122154) # Ühe isendimuutuja info väljastamine print(õppur1.eesnimi) print(õppur2.eesnimi) # Isendimuutuja tekitamine/muutmine ja vastava info väljastamine õppur1.lemmikloom = "koer" print(õppur1.lemmikloom) # Isendimeetodi rakendamine print(õppur1.sugu()) # Väljastamine, mis kasutab meetodit __str__ print(õppur1) print(õppur2) # Rakendame meetodit läbi_aine isendiga õppur1 kaks korda ja väljastame tema läbitud ainete arvu õppur1.läbi_aine() õppur1.läbi_aine() print(õppur1.läbitud_ainete_arv) # Isendid järjendis õppurid = [õppur1, õppur2] for el in õppurid: print(el.eesnimi, el.perenimi + ", isikukood:", el.isikukood)