Eelmise nädala loengu meeldetuletuseks¶
Näide: Auto ja selle asukoht. Maagilise meetodu __init__
esimene positionaalne argument self
tähistame loodavat objekti ning selle kaudu defineeritakse objekti muutujaid ja muid seotud andmeid. Igal loodud objektiga käivad kaasas selle enda andmed ja meetodid.
class Auto:
def __init__(self, kiirus = 0): # Konstruktor. Maagiline meetod mis konstrueerib objekti.
self.kiirus = kiirus # Objektimuutuja ehk atribuut.
def set_kiirus(self, kiirus): # Meetod 1. Setter funktsioon.
self.kiirus = kiirus # Kirjutan olemasoleva väärtuse üle.
def get_asukoht(self, aeg): # Meetod 2. Getter funktsioon.
return self.kiirus * aeg
def __repr__(self): # Maagiline meetod, esitus sõnena.
return 'Auto kiirusega {}.'.format(self.kiirus)
auto = Auto() # Loon auto objekti kasutades klassi Auto.
print(auto)
auto.set_kiirus(60) # [km/h]
print(auto.get_asukoht(0.5)) # [h]
print(auto)
auto
Auto kiirusega 0. 30.0 Auto kiirusega 60.
Auto kiirusega 60.
Mis vahet on maagilistel meetoditel __repr__
ja __str__
, millal millist kasutada? Eelmine nädal mainisime, et mõlemad on objekti esitamiseks sõne kujul konsoolis või mujal. Mis neil vahet on:
- Meetod
__repr__
:- Kasutame koodi aremdamise ajal.
- Esitab objekti andmeid detailsemalt.
- Vaikimisi juht kõigi sõne esituste jaoks.
- Meetod
__str__
:- Kasutame objekti esitamiseks lõppkasutaja jaoks.
- Vähem tehnilisi andmeid, vähem detailsem.
- Kui meetod
__str__
pole defineeritud/üle kirjutatud kasutatake vaikimisi meetodi__repr__
väljundit.
Klassi abil saime luua mitu objekti. Loon teise auto objekti kasutades klassi Auto
:
teine_auto = Auto()
teine_auto.set_kiirus(100) # [km/h]
teine_auto.get_asukoht(2.0) # [h]
200.0
Klassi meetodite dekoraatorid¶
Klassides kasutamiseks on loodud dekoraatorid millega same dekoreerida klassi meetodeid. Dokoraator muudab meetodi käitumist, vrd. Loeng 8.
Valik sisseehitatud meetodite dekoraatoreid:
@property
- Dünaamiline klassimuutuja või dünaamiline atribuut: Meetod käitub nagu klassimuutuja, väljakutse kujul<objekt>.<meetodi nimi>
(sulud puuduvad).@classmethod
- Klassimeetod: Meetod mis ei sõltu objektist (self
). Saame endiselt meetodi välja kutsuda kujul<Klassi nimi>.<meetodi nimi>()
ja jääb ka võimalus teha väljakutset läbi objekti, kujul<objekt>.<meetodi nimi>()
. Annab juurdepääsu mõjutada klassimuutujaid mis teatavati kehtivad kogu klassile (kõik objektid, kõik meetodid). Meetodi defineerimisel peame kasutama argumeticls
esimese positsionaalse argumendina.@staticmethod
- Staatiline meetod: Sõltumatu nii klassist (cls
) kui ka tema objektidest (self
).
Märkus 1: Pythonis esineb ka muid klassis kasutamiseks mõeldud dekoraatoreid. Siin kursuse vaatleme kõigest kolem eelmainitud.
Märkus 2: Selles kursuses käsitleme dekoraatorit @property
ja selle poolt loodud atribuute lihtsustatud kujul. Tudengid kes on huvitatud täielikumast ülevaatest, lugege järgmist: https://docs.python.org/3/library/functions.html#property
Meetodi dekoraator @property
¶
Meetodi dekoraatori @property
kasutamise näide:
class Auto:
def __init__(self, mudel, hind):
self.mudel = mudel # Objekti muutuja.
self.hind = hind # Objekti muutuja.
@property
def mudel_ja_hind(self):
return '{}, {}'.format(self.mudel, self.hind)
auto = Auto('BMW', 4000) # Loon objekti auto.
print(auto.mudel_ja_hind) # Meetod mis käitub nagu klassimuutuja.
BMW, 4000
Kuna tegemist pole enam tavalise meetodiga siis väljakutse kujul auto.mudel_ja_hind()
ja Auto.mudel_ja_hind(auto)
pole enam võimalik:
auto.mudel_ja_hind()
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[4], line 1 ----> 1 auto.mudel_ja_hind() TypeError: 'str' object is not callable
print(Auto.mudel_ja_hind(auto))
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[5], line 1 ----> 1 print(Auto.mudel_ja_hind(auto)) TypeError: 'property' object is not callable
Meetodi dekoraator @classmethod
¶
Meetodi dekoraatori @classmethod
kasutamise näide:
class Auto:
allahindlus = 0.95 # Klassimuutuja.
def __init__(self, mudel, hind):
self.mudel = mudel # Objekti muutuja.
self.hind = hind # Objekti muutuja.
def alanda_hinda(self):
self.hind = Auto.allahindlus * self.hind
@classmethod
def allahindlus_maar(cls, protsent): # NB! cls.
cls.allahindlus = protsent # Staatiline klassimuutuja.
auto = Auto('BMW', 4000)
print(Auto.allahindlus) # Klassimuutuja järelevaatamine, otse.
print(auto.allahindlus) # Klassimuutuja, läbi loodud objekti.
Auto.allahindlus_maar(0.90) # Uus allahindlusmäär, kehtib kogu klassile.
print(Auto.allahindlus) # Klassimuutuja järelevaatamine, otse.
print(auto.allahindlus) # Klassimuutuja, läbi loodud objekti.
auto.alanda_hinda() # Hinna alandamine.
print(auto.hind) # Uus hind.
teine_auto = Auto('Audi', 2000)
print(teine_auto.allahindlus) # Klassimuutuja, läbi uue objekti.
0.95 0.95 0.9 0.9 3600.0 0.9
Meetodi dekoraator @staticmethod
¶
Meetodi dekoraatori @staticmethod
kasutamise näide:
class Auto:
def __init__(self, mudel, hind):
self.mudel = mudel
self.hind = hind
@staticmethod
def on_lahe_auto(mudelnimi): # Ei sõltu argumentidest cls ega self.
if mudelnimi == 'BMW':
return True
else:
return False
auto = Auto('BMW', 4000)
print(Auto.on_lahe_auto('Ford')) # Väljakutse läbi klassi.
print(Auto.on_lahe_auto('BMW')) # Väljakutse läbi klassi.
print(auto.on_lahe_auto('Ford')) # Väljakutse läbi objekti.
print(auto.on_lahe_auto('BMW')) # Väljakutse läbi objekti.
False True False True
class A:
cls_A = 1
def cls_A_method(self):
print('Class A method.')
class B:
cls_B = 2
def cls_B_method(self):
print('Class B method.')
class C(A, B): # Pärimiene klassist A ja siis klassis B.
cls_C = 3
def cls_C_method(self):
print('Class C method.')
# Väljakutsed kasutades klassi C.
print(C.cls_A) # Päritud.
print(C.cls_B) # Päritud.
print(C.cls_C)
cls_C_obj = C() # Objekti loomine.
C.cls_A_method(cls_C_obj) # Päritud.
C.cls_B_method(cls_C_obj) # Päritud.
C.cls_C_method(cls_C_obj)
# Väljakutsed kasutades klassi C objekti.
print(cls_C_obj.cls_A) # Päritud.
print(cls_C_obj.cls_B) # Päritud.
print(cls_C_obj.cls_C)
cls_C_obj.cls_A_method() # Päritud.
cls_C_obj.cls_B_method() # Päritud.
cls_C_obj.cls_C_method()
1 2 3 Class A method. Class B method. Class C method. 1 2 3 Class A method. Class B method. Class C method.
Päritud atribuute saab loomulikult üle kirjutada:
class A:
cls_A = 1
def cls_A_method(self):
print('Class A method.')
class B:
cls_B = 2
def cls_B_method(self):
print('Class B method.')
class C(A, B): # Pärimiene klassist A ja B.
cls_A = 111 # Kasutan nime muudan sisu.
def cls_B_method(self): # Kasutan nime muudan sisu.
print('Class B üle kirjutatud method.')
# Väljakutsed kasutades klassi C.
print(C.cls_A) # Päritud ja üle kirjutatud.
print(C.cls_B) # Päritud.
cls_C_obj = C() # Objekti loomine.
C.cls_A_method(cls_C_obj) # Päritud.
C.cls_B_method(cls_C_obj) # Päritud ja üle kirjutatud.
# Väljakutsed kasutades klassi C objekti.
print(cls_C_obj.cls_A) # Päritud ja üle kirjutatud.
print(cls_C_obj.cls_B) # Päritud.
cls_C_obj.cls_A_method() # Päritud.
cls_C_obj.cls_B_method() # Päritud ja üle kirjutatud.
111 2 Class A method. Class B üle kirjutatud method. 111 2 Class A method. Class B üle kirjutatud method.
Mida ütleb method resolution order (MRO)?
C.mro()
[__main__.C, __main__.A, __main__.B, object]
C.__mro__
(__main__.C, __main__.A, __main__.B, object)
Seega sulgudesse paigutatud superklasside järjekord on oluline.
Mitmest superklassist pärimine ja transitiivsus¶
Päritavad superklassid saavad omakorda pärida kolmandatest superklassidest jne. Allolevas näites olevate superklasside sisu (klassimuutujad, objektimuuutjad ja meetodid) pärandatakse alamklassile:
class A:
cls_A = 1
def cls_A_method(self):
print('Class A method.')
class B(A): # Pärib klassi A sisu.
cls_B = 2
def cls_B_method(self):
print('Class B method.')
class C(B): # Pärib klassi B sisu, mis omakorda päris ka klassi A sisu.
cls_C = 3
def cls_C_method(self):
print('Class C method.')
# Väljakutsed kasutades klassi C.
print(C.cls_A) # Päritud läbi klassi B.
print(C.cls_B) # Päritud klassist B.
print(C.cls_C)
cls_C_obj = C() # Objekti loomine.
C.cls_A_method(cls_C_obj) # Päritud läbi klassi B.
C.cls_B_method(cls_C_obj) # Päritud klassist B.
C.cls_C_method(cls_C_obj)
# Väljakutsed kasutades klassi C objekti.
print(cls_C_obj.cls_A) # Päritud läbi klassi B.
print(cls_C_obj.cls_B) # Päritud klassist B.
print(cls_C_obj.cls_C)
cls_C_obj.cls_A_method() # Päritud läbi klassi B.
cls_C_obj.cls_B_method() # Päritud klassist B.
cls_C_obj.cls_C_method()
1 2 3 Class A method. Class B method. Class C method. 1 2 3 Class A method. Class B method. Class C method.
Pärimise omadust kus alamklass D
pärib mitmest superklassist (A
, B
, C
) järgmiselt: A
$\to$ B(A)
$\to$ C(B)
$\to$ D(C)
, nimetatakse transitiivsuseks. Eelmises lauses olevas näites, oleks pärimiste järjestikune jada saanud olla meelevaldselt pikk.
Konstruktori pärimine, funktsioon super
ja alamklassi objekti laiendamine¶
Klassid saavad pärida teiste klasside kõiki atribuute k.a. initsialiseeringuid mis on defineeritud maagilises meetodis __init__
ehk konstruktoris.
Konstruktori pärimine¶
Näide milles päritakse konstruktor ehk maagiline meetod __init__
ilma selle andmete struktuuri ja sisu muutmata. Me teame, et saame kasutada klassi nime viitamaks selle meetoditele, seega:
class Inimene: # Superklass.
def __init__(self, nimi, perenimi, sugu):
self.nimi = nimi
self.perenimi = perenimi
self.sugu = sugu
class Tudeng(Inimene): # Alamklass.
def __init__(self, nimi, perenimi, sugu):
# Viitan konstruktorile läbi superklassi nime.
Inimene.__init__(self, nimi, perenimi, sugu) # NB! Argument self.
Juulia = Inimene('Juulia', 'Tipikas', 'naine')
Juulius = Tudeng('Juulius', 'Tipikas', 'mees') # Initsialiseering töötab.
print(Juulia.sugu)
print(Juulius.sugu) # Initsialiseering töötab.
naine mees
Konstruktori pärimine ja sisseehitatud funktsioon super
¶
Sisseehitatud funktsioon super
võimaldab viidata superklassi meetoditele alamklassi seest, k.a. konstruktorile ilma, et sa peaksid klassi nimele ilmutatud kujul viitama seda nimepidi kutsudes. Funktsiooni super
kasutame peamiselt initsialiseeringute pärimisel. Lisaks kasutatakse seda ka transitiivsel konstruktorite pärimisel ülevaate hoidmiseks.
class Inimene: # Superklass.
def __init__(self, nimi, perenimi, sugu):
self.nimi = nimi
self.perenimi = perenimi
self.sugu = sugu
class Tudeng(Inimene): # Alamklass
def __init__(self, nimi, perenimi, sugu):
super().__init__(nimi, perenimi, sugu) # NB! Argument self puudub.
Juulia = Inimene('Juulia', 'Tipikas', 'naine')
Juulius = Tudeng('Juulius', 'Tipikas', 'mees') # Initsialiseering töötab.
print(Juulia.sugu)
print(Juulius.sugu) # Initsialiseering töötab.
naine mees
Konstruktori pärimine ja alamklassi objekti laiendamine¶
Kui soovime alamklassis laiendada initsialiseeringut, nt. ksutada uusi objekti muutujaid, saame seda teha järgmiselt:
- Initsialiseerime kasutades superklassi nime.
class Inimene:
def __init__(self, nimi, perenimi, sugu):
self.nimi = nimi
self.perenimi = perenimi
self.sugu = sugu
class Tudeng(Inimene):
def __init__(self, nimi, perenimi, sugu, iq):
Inimene.__init__(self, nimi, perenimi, sugu)
self.iq = iq # Lisan uue objekti muutuja.
Juulia = Inimene('Juulia', 'Tipikas', 'naine')
Juulius = Tudeng('Juulius', 'Tipikas', 'mees', 100)
print(Juulia.sugu)
print(Juulius.sugu)
print(Juulius.iq)
naine mees 100
- Initsialiseerime kasutades funktsiooni
super
. Kasutades funktsioonisuper
saame sama tulemuse.
class Inimene:
def __init__(self, nimi, perenimi, sugu):
self.nimi = nimi
self.perenimi = perenimi
self.sugu = sugu
class Tudeng(Inimene):
def __init__(self, nimi, perenimi, sugu, iq):
super().__init__(nimi, perenimi, sugu)
self.iq = iq # Lisan uue objekti muutuja.
Juulia = Inimene('Juulia', 'Tipikas', 'naine')
Juulius = Tudeng('Juulius', 'Tipikas', 'mees', 100)
print(Juulia.sugu)
print(Juulius.sugu)
print(Juulius.iq)
naine mees 100
Superklassi meetodile viitamine alamklassi seest ja funktsioon super
¶
Meetodite pärimine on meile tuttav juba eelmise nädala loengust. Me teame, et pärime kõik superklassi meetodid seda pärides.
Lisame klassile Inimene
meetodi to_string
mis prindib objekti andmed. Pärime selle klassi alamklassi nimega Tudeng
. Alamklassis Tudeng
viitame meetodile to_string
ja teeme selle väljakutse (võid ka muid asju teha) kasutades superklassi nime ja funktsiooni super
:
class Inimene:
def __init__(self, nimi, perenimi, sugu):
self.nimi = nimi
self.perenimi = perenimi
self.sugu = sugu
def to_string(self):
print(f'Nimi on {self.nimi} {self.perenimi}.')
class Tudeng(Inimene):
def __init__(self, nimi, perenimi, sugu):
super().__init__(nimi, perenimi, sugu)
def meetod_1(self):
Inimene.to_string(self) # Viide meetodile kasutades klassi nime.
def meetod_2(self):
super().to_string() # Viide meetodile kasutades funktsiooni super.
Juulius = Tudeng('Juulius', 'Tipikas', 'mees')
Juulius.to_string() # Superklassis defineeitud ja päritud.
Juulius.meetod_1() # Superklassis defineeitud.
Juulius.meetod_2() # Superklassis defineeitud.
Nimi on Juulius Tipikas. Nimi on Juulius Tipikas. Nimi on Juulius Tipikas.
Pesastatud klassid¶
Klasse nii nagu kõiki muid Pythoni blokke on võimalik üksteise sisse pesastada. All on näide klassist mis defineerib objekti tudeng kellega on seotud objekt mobiiltelefon ning kes saab sellega uhkustada ja helistada etteantud numbrile.
Märkus 3: Alloleva näite saab lahendada ka kasutades kahte eraldi klassi.
class Tudeng:
def __init__(self, nimi, perenimi):
self.nimi = nimi
self.perenimi = perenimi
self.mobiiltelefon = self.Mobiil() # Loon objekti viidates klassile Mobiil. NB! sulud.
class Mobiil:
def __init__(self):
self.tootja = "LG"
self.mudel = 'LM50PM'
self.number = 12345678
def uhkusta(self):
return 'Mul on {} {} ja minu telefoninumber on {}.'.format(self.tootja, self.mudel, self.number)
def helista(self, number):
print('Helistamine numbrile {} toimub.'.format(number))
tudeng = Tudeng('Juulius', 'Tipkas')
print(tudeng.mobiiltelefon.tootja)
print(tudeng.mobiiltelefon.mudel)
print(tudeng.mobiiltelefon.number)
tudeng.mobiiltelefon.helista(112) # Läbi konstruktori initsialiseerimise.
print(tudeng.mobiiltelefon.uhkusta()) # Läbi konstruktori initsialiseerimise.
mobiil = Tudeng.Mobiil() # Pesastatud klassiga objekti loomine.
print(mobiil)
LG LM50PM 12345678 Helistamine numbrile 112 toimub. Mul on LG LM50PM ja minu telefoninumber on 12345678. <__main__.Tudeng.Mobiil object at 0x137ed1f10>
Vajadusel võime pesastatud meetodite väljakutseid lühendada luues pesastava klassi skoopi meetodid mis viitavad pesastatud klassi lokalse skoobi meetoditele:
class Tudeng:
def __init__(self, nimi, perenimi):
self.nimi = nimi
self.perenimi = perenimi
self.mobiiltelefon = self.Mobiil()
def uhkusta(self): # Tekitasin viite pesastatud meetodi objektile.
return self.mobiiltelefon.uhkusta()
def helista(self, num): # Tekitasin viite pesastatud meetodile.
return self.mobiiltelefon.helista(num)
class Mobiil:
def __init__(self):
self.tootja = "LG"
self.mudel = 'LM50PM'
self.number = 12345678
def uhkusta(self):
return 'Mul on {} {} ja minu telefoninumber on {}.'.format(self.tootja, self.mudel, self.number)
def helista(self, number):
print('Helistamine numbrile {} toimub.'.format(number))
tudeng = Tudeng('Juulius', 'Tipkas')
print(tudeng.mobiiltelefon.tootja)
print(tudeng.mobiiltelefon.mudel)
print(tudeng.mobiiltelefon.number)
tudeng.mobiiltelefon.helista(112) # Läbi konstruktori initsialiseerimise.
tudeng.helista(911) # Taustal kasutame loodud viidet.
print(tudeng.mobiiltelefon.uhkusta()) # Läbi konstruktori initsialiseerimise.
print(tudeng.uhkusta()) # Taustal kasutame loodud viidet.
LG LM50PM 12345678 Helistamine numbrile 112 toimub. Helistamine numbrile 911 toimub. Mul on LG LM50PM ja minu telefoninumber on 12345678. Mul on LG LM50PM ja minu telefoninumber on 12345678.
Kapseldamine¶
Teatavasti saame klassi- ja objekti muutujatele ligi globaalses skoobis kuna class
-blokk ei kapselda muutujaid (see pole def
-blokk). Sellist käitumist saab muuta kapseldades muutujaid ja meetodeid.
Näide kapseldamata klassimuutujatest, objekti muutujatest ja meetodist ehk avalikest klassimuutujatest, objekti muutujatest ja meetodist:
class A:
cls_A_a = 1
cls_A_b = 22
def __init__(self, obj_a, obj_b):
self.obj_a = obj_a
self.obj_b = obj_b
def cls_A_method(self):
return 'obj_a = {} and obj_b = {}'.format(self.obj_a, self.obj_b)
obj = A(3, 44)
print(A.cls_A_b) # Klassimuutuja.
print(obj.obj_b) # Objekti muutuja.
print(obj.cls_A_method()) # Meetodi väljakutse.
print(A.cls_A_method(obj)) # Meetodi väljakutse läbi klassi.
22 44 obj_a = 3 and obj_b = 44 obj_a = 3 and obj_b = 44
Eelnäidatud kood on täiesti hea kui sa kodeerid enda jaoks ja kasutad klassi nagu sa oled seda enda peas ette kujutanud. Sinu programmi võib aga ksutada keegi teine. Kuid klassi kasutaja, kes pole klassi programmeerija mõtetega tuttav, võib käituda näiteks järgmiselt:
class A:
cls_A_a = 1
cls_A_b = 22
def __init__(self, obj_a, obj_b):
self.obj_a = obj_a
self.obj_b = obj_b
def cls_A_method(self):
return 'obj_a = {} and obj_b = {}'.format(self.obj_a, self.obj_b)
obj = A(3, 44)
print(obj.cls_A_method())
# Saame klassi- ja objekti muutujad vabalt üle kirjutada.
A.cls_A_b = 'Häkitud number.'
obj.obj_b = 'Häkitud objekti muutuja.'
print(A.cls_A_b)
print(obj.obj_b)
# See omakorda muudab meetodite käitumise.
print(obj.cls_A_method())
# Võime meetodi hoopis hävitada.
obj.cls_A_method = 'Häkitud meetod.'
print(obj.cls_A_method) # Väljakutse kujul obj.cls_A_method() võimatu.
obj_a = 3 and obj_b = 44 Häkitud number. Häkitud objekti muutuja. obj_a = 3 and obj_b = Häkitud objekti muutuja. Häkitud meetod.
Selleks, et eelolevat olukorda vältida saame klassi atribuudid kapseldada ehk muuta need privaatseks eesmärgiga kaitsta neid globaalse skoobi juurdepääsu eest. Mäletatavasti kapseldav skoop lokaliseeris muutujad kasutamiseks ainult sellest skoobist. Meetodi kapseldamisel jääb see kasutamiseks ainult klassi bloki sees ja seest.
Atribuute kapseldame kasutades kahte alakriipsu muutuja või meetodi nime ees, nt. foo
$\to$ __foo
, bar()
$\to$ __bar()
jne.:
class A:
cls_A_a = 1 # Avalik klassimuutuja.
__cls_A_b = 22 # Kapseldatud ehk privaatne klassimuutuja.
def __init__(self, obj_a, obj_b):
self.obj_a = obj_a # Avalik objekti muutuja.
self.__obj_b = obj_b # Kapseldatud ehk privaatne objekti muutuja.
def __cls_A_method(self): # Kapseldatud ehk privaatne meetod.
return 'obj_a = {} and obj_b = {}.'.format(self.obj_a, self.__obj_b)
def data(self): # Avalik meetod.
obj_b_id = id(self.__obj_b)
return 'obj_b = {}, obj_b id = {}.'.format(self.__obj_b, obj_b_id)
obj = A(3, 44)
print(obj.data())
obj_b = 44, obj_b id = 4344999312.
Väljakutsed kujul:
print(obj.obj_b) # Juurdepääs puudub.
print(obj.__obj_b) # Juurdepääs puudub.
print(obj.cls_A_method) # Juurdepääs puudub.
print(obj.cls_A_method()) # Juurdepääs puudub.
print(obj.__cls_A_method()) # Juurdepääs puudub.
print(A.cls_A_b) # Juurdepääs puudub.
print(A.cls_A_method(obj)) # Juurdepääs puudub.
print(A.__cls_A_method(obj)) # Juurdepääs puudub.
tõstatavad erisuse AttributeError
. Näiteks:
print(obj.obj_b)
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Cell In[23], line 1 ----> 1 print(obj.obj_b) AttributeError: 'A' object has no attribute 'obj_b'
NB! Kapseldatud atribuutidege klassi puhul näitab funktsioon dir
kapseldamata ehk avalikke atrubuute loendi lõpus:
print(dir(A))
['_A__cls_A_b', '_A__cls_A_method', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'cls_A_a', 'data']
Usinam tudeng võis juba märgata, et globaalses skoobis saame luua uusi objekte (erinev id) kasutades kapseldatud atribuutide nimesid. Need kehtivad ainult globaalses skoobis ja ei mõjuta klassi atribuute. Kontrollime ja vaatame kas väljakutse id(obj.obj_b)
väärtus erined klassisisesest väärtusest:
obj.obj_b = 'Häkitud muutuja' # Uus objekt.
obj.__obj_b = 'Häkitud __muutuja.' # Uus objekt.
obj.cls_A_method = 'Häkitud meetod.' # Uus objekt.
obj.__cls_A_method = 'Häkitud __meetod.' # Uus objekt.
print(obj.obj_b, 'id =', id(obj.obj_b), 'erineb kapseldatud muutuja omast.')
print(obj.__obj_b)
print(obj.cls_A_method)
print(obj.__cls_A_method)
Häkitud muutuja id = 5232907280 erineb kapseldatud muutuja omast. Häkitud __muutuja. Häkitud meetod. Häkitud __meetod.
Kapseldatud muutuja on tõesti peidetud globaalse skoobi eest, veel üks näide lisaks infole eelmises lõigus:
class Auto:
def __init__(self):
self.__hind = 100
def müü_auto(self):
print(f"Auto müüdud hinnaga {self.__hind}.")
def määra_hind(self, hind):
self.__hind = hind
mersu = Auto()
# Müüme vaikimisi hinnaga.
mersu.müü_auto()
# (Püüan) muuta hinda ja müün.
mersu.__hind = 5000
mersu.müü_auto() # NB! Ei õnnestu!
# Määran uue hinna läbi meetodi määra_hind ja müün.
mersu.määra_hind(5000)
mersu.müü_auto()
Auto müüdud hinnaga 100. Auto müüdud hinnaga 100. Auto müüdud hinnaga 5000.
Lisa: Näiteid kodus uurimiseks¶
Siin viidatud lisas esitame erinevaid näiteid klasside defineerimise ja nende kasutamise kohta.