Loeng 12: Objektorienteeritud programmeerimine (OOP), klass, konstruktor ja spetsiaalne meetod __init__
, objekt, meetodi defineerimine, klassi staatiline muutuja, spetsiaalne meetod, pärilikkus, plümorfism, lausend: class
, muutuja self
, funktsioonid: isinstance
, issubclass
, jm.¶
Lisa: Näiteid iseseisvalt uurimiseks¶
Allpool on hulk kommenteeritud klasside loomisega ja nende objektidega opereerimise näiteid. Allolevad klassid defineerivad TTÜ tudengite objekte ehk tudengeid.
Klassimuutujad, objekti muutujad ja meetodid¶
Tühi klass:
class Tudeng0:
pass
tudeng1 = Tudeng0() # Loome objekti, sulud vajalikud.
tudeng2 = Tudeng0()
print(tudeng1)
print(tudeng2)
print(type(tudeng1))
<__main__.Tudeng0 object at 0x11d481b10> <__main__.Tudeng0 object at 0x11d481b50> <class '__main__.Tudeng0'>
Lisame käsitsi ülal loodud tudengitele objektimuutujad (pole soovitatav käitumine):
tudeng1.eesnimi = 'Juulius' # Muutuja, pole sulge.
tudeng1.perenimi = 'Tipikas'
tudeng1.email = 'juulus.tipikas@taltech.ee'
tudeng1.stipp = 200
tudeng1.kutsumus = 'maskott'
tudeng1.sugu = 'mees'
tudeng2.eesnimi = 'Mari'
tudeng2.perenimi = 'Tamm'
tudeng2.email = 'mari.tamm@taltech.ee'
tudeng2.stipp = 100
# Kontroll või andmete kasutamine:
print(tudeng1.email)
print(tudeng2.email)
print("TalTech'i Juulius Tipikas on {} ja ta on {}!".format(tudeng1.kutsumus, tudeng1.sugu))
juulus.tipikas@taltech.ee mari.tamm@taltech.ee TalTech'i Juulius Tipikas on maskott ja ta on mees!
Käsitsi objekti muutujate sisestamine pole mugav. Spetsiaalne meetod __init__
aitab seda tegevust automatiseerida:
class Tudeng:
def __init__(self, eesnimi, perenimi, sugu, stipp): # Argument self = objekt, class instance.
self.eesnimi = eesnimi # Instance variables
self.perenimi = perenimi
self.sugu = sugu
self.stipp = stipp
self.email = self.eesnimi + '.' + self.perenimi + '@taltech.ee'
tudeng1 = Tudeng('Juulius', 'Tipkas', 'mees', 200) # Loome objekti.
tudeng2 = Tudeng('Mari', 'Tamm', 'naine', 300)
print(tudeng1)
print(tudeng2)
print(tudeng1.email)
print(tudeng2.email)
print(tudeng1.eesnimi, tudeng1.perenimi, 'on', tudeng1.sugu)
<__main__.Tudeng object at 0x11d4b4610> <__main__.Tudeng object at 0x11d483490> Juulius.Tipkas@taltech.ee Mari.Tamm@taltech.ee Juulius Tipkas on mees
Loome klassimeetodi mis väljastab tudengi ees- ja perekonnanimed ühes sõnes:
class Tudeng:
def __init__(self, eesnimi, perenimi, stipp):
self.eesnimi = eesnimi
self.perenimi = perenimi
self.stipp = stipp
self.email = eesnimi + '.' + perenimi + '@taltech.ee'
def taisnimi(self): # Meetod.
return '{} {}'.format(self.eesnimi, self.perenimi)
tudeng1 = Tudeng('Juulius', 'Tipkas', 200)
tudeng2 = Tudeng('Mari', 'Tamm', 100)
print(tudeng1.taisnimi) # Meetodi nimi.
print(tudeng1.taisnimi()) # Meetodi väljakutse, sulud vajalikud.
# Saan meetodi välja kutsude kasutades klassi nime:
print(Tudeng.taisnimi(tudeng2))
<bound method Tudeng.taisnimi of <__main__.Tudeng object at 0x11d4b5cd0>> Juulius Tipkas Mari Tamm
Lisame meetodi mis muudab objektimuutuja stipp
väärtust. Tõstame seda 5% võrra:
class Tudeng:
def __init__(self, eesnimi, perenimi, stipp):
self.eesnimi = eesnimi
self.perenimi = perenimi
self.stipp = stipp
self.email = eesnimi + '.' + perenimi + '@taltech.ee'
def taisnimi(self):
return '{} {}'.format(self.eesnimi, self.perenimi)
def stippi_tostmine(self): # Meetod mis tõstab stippi väärtust.
self.stipp = int(1.05 * self.stipp)
tudeng1 = Tudeng('Juulius', 'Tipkas', 200)
tudeng2 = Tudeng('Mari', 'Tamm', 300)
print(tudeng1.stipp)
tudeng1.stippi_tostmine() # Tõstan tudeng1 stippi.
print(tudeng1.stipp)
200 210
Klassi- või staatilised muutujad¶
Klassi staatilised muutujad on kehtivad kõigile klassi poolt loodud objektidele:
class Tudeng:
tosta_stipp = 1.05 # Klassimuutuja, staatiline muutuja.
def __init__(self, eesnimi, perenimi, stipp):
self.eesnimi = eesnimi
self.perenimi = perenimi
self.stipp = stipp
def taisnimi(self):
return '{} {}'.format(self.eesnimi, self.perenimi)
def stippi_tostmine(self): # Meetod mis tõstab stippi.
self.stipp = int(Tudeng.tosta_stipp * self.stipp)
# NB! Võib ka: self.tosta_stipp
tudeng1 = Tudeng('Juulius', 'Tipkas', 200)
tudeng2 = Tudeng('Mari', 'Tamm', 300)
print(tudeng1.stipp)
tudeng1.stippi_tostmine() # Tõstan tudeng1 stippi.
print(tudeng1.stipp)
200 210
Saame muutuja tosta_stipp
väärtuse järgi vaadata, nii viidates klassile kui ka obejtidele:
print(Tudeng.tosta_stipp) # Põhjus miks on klassimuutuja.
print(tudeng1.tosta_stipp) # Jagatud kõigi objektide vahel.
print(tudeng2.tosta_stipp) # Jagatud kõigi objektide vahel.
1.05 1.05 1.05
Kui soovid muuta stipi tõstmise protsenti kogu klassile ja väljastpoolt klassi definitsiooni:
Tudeng.tosta_stipp = 1.01 # Uus väärtus.
print(Tudeng.tosta_stipp)
print(tudeng1.tosta_stipp)
print(tudeng2.tosta_stipp)
1.01 1.01 1.01
Tahan muuta stipi tõstmise protsenti ainult kindlale tudengil, nt. tudeng1
:
tudeng1.tosta_stipp = 1.21
print(Tudeng.tosta_stipp)
print(tudeng1.tosta_stipp)
print(tudeng2.tosta_stipp)
1.01 1.21 1.01
Näide olukorrast kus objekt ei tohiks klassimuutujat muuta. Kooli vastuvõetud tudengite arv, kes saavad stippi, ei tohi muutuda objekti tasemel:
class Tudeng:
tudengite_arv = 0 # Klassimuutuja.
tosta_stipp = 1.05 # Klassimuutuja.
def __init__(self, eesnimi, perenimi, stipp):
self.eesnimi = eesnimi
self.perenimi = perenimi
self.stipp = stipp
self.email = eesnimi + '.' + perenimi + '@taltech.ee'
Tudeng.tudengite_arv += 1 # Iga uus tudeng inkrementeerib.
print(Tudeng.tudengite_arv, 'pole veel lisanud.')
tudeng1 = Tudeng('Juulius', 'Tipkas', 200)
tudeng2 = Tudeng('Mari', 'Tamm', 300)
print(Tudeng.tudengite_arv) # Kaks tud. on meetodist __init__ läbi käinud.
print(tudeng1.tudengite_arv) # Kõigile sama.
print(tudeng2.tudengite_arv) # NB! Ära kirjuta üle.
0 pole veel lisanud. 2 2 2
Spetsiaalsete meetodide ülekirjutamine¶
Näide 1: Meetodite __repr__
ja __str__
näitel.
class Tudeng:
tosta_stipp = 1.05
def __init__(self, eesnimi, perenimi, stipp): # Dunder method.
self.eesnimi = eesnimi
self.perenimi = perenimi
self.stipp = stipp
self.email = eesnimi + '.' + perenimi + '@taltech.ee'
def __repr__(self): # Kirjutan olemasoleva üle.
return "REPR: {}('{}', '{}', '{}')".format(type(self).__name__, self.eesnimi,
self.perenimi,
self.stipp)
def __str__(self): # Kirjutan olemasoleva üle.
return 'STR: {} {} kes saab {} eurot stippi.'.format(self.eesnimi,
self.perenimi,
self.stipp)
tudeng1 = Tudeng('Juulius', 'Tipkas', 200)
print(repr(tudeng1))
print(str(tudeng1))
print(tudeng1)
print(tudeng1.__repr__())
print(tudeng1.__str__())
REPR: Tudeng('Juulius', 'Tipkas', '200') STR: Juulius Tipkas kes saab 200 eurot stippi. STR: Juulius Tipkas kes saab 200 eurot stippi. REPR: Tudeng('Juulius', 'Tipkas', '200') STR: Juulius Tipkas kes saab 200 eurot stippi.
Näide 2: Meetodite __add__
ja __len__
näitel. Loome meetodi mis suudab liita tudengeid ja leida tudengi täisnime pikkuse ehk tähemärkide arvu.
class Tudeng:
def __init__(self, eesnimi, perenimi, stipp):
self.eesnimi = eesnimi
self.perenimi = perenimi
self.stipp = stipp
self.email = eesnimi + '.' + perenimi + '@taltech.ee'
def taisnimi(self):
return '{} {}'.format(self.eesnimi, self.perenimi)
def __add__(self, other): # Kahe tudengi liitmine.
return self.stipp + other.stipp # Eeldan, et otheril on muutuja stipp.
def __len__(self): # Nime pikkus.
return len(self.taisnimi())
tudeng1 = Tudeng('Juulius', 'Tipkas', 200)
tudeng2 = Tudeng('Mari', 'Tamm', 300)
print('\nStippede summa:')
print(tudeng1 + tudeng2)
print(tudeng1.__add__(tudeng2))
print(Tudeng.__add__(tudeng1, tudeng2))
print('\nTudengi taisnimi:')
print(tudeng1.taisnimi())
print('\nTudengi nime tähtede arv:')
print(len(tudeng1))
Stippede summa: 500 500 500 Tudengi taisnimi: Juulius Tipkas Tudengi nime tähtede arv: 14