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.¶

Viimati uuendatud 19.11.2024.

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:

In [1]:
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):

In [2]:
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:

In [3]:
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:

In [4]:
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:

In [5]:
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:

In [6]:
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:

In [7]:
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:

In [8]:
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:

In [9]:
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:

In [10]:
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.

In [11]:
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.

In [12]:
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

















☻   ☻   ☻