Previous slide Next slide Toggle fullscreen Open presenter view
Objekt-orienteeritud programmeerimine
object-oriented programming (OOP)
Objekt
Objekt kirjeldab ära konkreetse loogilise kogumi
näiteks õues olev punane auto on üks objekt
selle taga olev roheline auto on teine objekt jne
Tavaliselt mõtleme me arvust kui ühest väärtusest (nt 7)
Objekt koosneb tavaliselt mitmest väärtusest
värv, mark, mudel, pikkus, registrimass jne
Klass
Klass kirjeldab ära struktuuri
näiteks autol on värv, pikkus jne
Klass (üldiselt) ei sisalda andmeid
Klass on andmetüüp
Samatüüpi andmed pärinevad kõik ühest klassist
punane auto on auto, roheline auto on auto jne
Kuigi meil on maailmas mitu autot (objekti), siis meil on üks klass auto
OOP
Objekt-orienteeritud programmeerimine (OOP) on programmeerimise paradigma, mis kasutab objekte
Python on objekti-orienteeritud programmeerimiskeel (OOP)
Pythonis kõik asjad on objektid
OOP tehnikad
Kapseldamine (encapsulation )
funktsionaalsus peidetakse
Modulaarsus (modularity )
programm jagatakse iseseisvateks tükkideks
Polümorfism (polymorphism )
alamklass saab meetodeid üle kirjutada
Pärimine (inheritance )
alamklass pärib omadused ja meetodid
Sõne
Sõne on objekt
Kui loote uue sõne, siis tegelikult luuakse uus objekt, mille tüüp on str
.
Sõne "funktsioone" kutsutakse meetoditeks
ehk siis klassis kirjeldatud funktsioonid on meetodid
Sõne
s = "Hello"
print (type (s))
print (id (s))
print (id (s.replace("H" , "h" )))
Loome sõne s
ja küsime selle tüübi. Tüüp on str
klass
id
tagastab objekti kohta unikaalse arvu. Kui id on erinev, siis on ka objekt erinev (st mälus erinevas kohas)
replace
teeb uue sõne, seda näeme ka id
-ga
replace
on sõne meetod ehk funktsioon, mida saab välja kutsuda objektil
List
a = [1 , 2 , 3 ]
b = [1 , 2 , 3 ]
c = b
print (id (a))
a.append(4 )
print (id (a))
print (id (b))
print (id (c))
b.pop()
print (id (b))
print (id (c))
Listi muutes id
ei muutu
c
ja b
viitavad samale listile
Veel objekte
print (type (1 ))
print (type (True ))
print (type (1.2 ))
print (type (None ))
print (type (len ))
print (type (type ))
Klass kui andmetüüp
Iga klass on andmetüüp
Näiteks on Pythonis klass str
Iga konkreetne sõne, näiteks "tere"
, on selle klassi objekt (ehk isend)
Ühest klassist saab luua lõpmata palju objekte
Objekti kohta öeldakse ka isend ja instants
Üldiselt mõeldakse "objekt", "isend", "instants" terminitega samu asju
Erinevates allikates võivad neil erinevused olla
Teeme oma klassi
class Student :
pass
s = Student()
print (type (s))
print (id (s))
t = Student()
print (type (t))
print (id (t))
Klass Student
. pass
on tühi korraldus
Loome kaks isendit - nende id
on erinev (nad on mälus erinevas kohas)
Objektide võrdlemine
Objektide võrdlemine ==
võrdlusega kontrollib vaikimisi seda, kas nad viitavad samale objektile
Seda, mida täpselt kontrollitakse, saab üle kirjutada
Näiteks sõne puhul kontrollitakse seda, kas sisu (st sümbolid) on samad jne
s1 = Student()
s2 = Student()
s3 = s1
print (s1 == s2)
print (s1 == s3)
print (s2 == s3)
Meetod
Klassis sisalduvaid funktsioone nimetatakse meetoditeks
class Student :
"""Student class."""
def hello (self ):
"""Method (function) which just prints out "Hello!"."""
print ("Hello!" )
s = Student()
s.hello()
self
Kõik objekti meetodid sisaldavad esimest parameetrit self
selle parameetri nimi võib ka midagi muud olla; kasutage self
self
viitab isendile
Eelmises näites oli väljakutse s.hello()
kui hello()
meetod käima pannakse, antakse sellele s
kaasa
Meetodi jaoks vajalike väärtuste jaoks lisatakse need peale self
parameetrit
self
ja parameetrid
class Student :
def greet_friend (self, friend_name ):
print (f"Hello, {friend_name} " )
s = Student()
s.greet_friend("Kaia" )
Meetodi kirjelduses esimesel kohal on self
, teisel kohal friend_name
.
Kui kutsume välja greet_friend
meetodit, siis esimesena kaasa antud argument läheb teise parameetrisse jne.
Konstruktor
Objekti loomisel pannakse käima eriline meetod ehk konstruktor
Meetod kirjeldatakse: __init__(self)
See meetod pannakse käima üks kord objekti loomisel
Eelnevas näites s = Student()
kutsub välja konstruktori
Konstruktori kirjeldamine ei ole kohustuslik
Konstruktor peab tagastama None
(eraldi return
lauset ei kirjutata).
Konstruktor
Kirjeldatakse nagu tavaline meetod
Eraldi pole vaja välja kutsuda
class Student :
def __init__ (self ):
print ("Initializing student.." )
s = Student()
Student()
kutsub Student
klassi konstruktori välja.
Konstruktor, objekti muutujad
self
viitab loodavale/loodud objektile
Konstruktorisse saab kaasa anda argumente (nagu tavaline funktsioon)
Esimene parameeter on alati self
Objekti muutujad on seotud ühe konkreetse objektiga (isendiga)
Objekti muutujaid väärtustatakse: self.name = ...
Tavaliselt luuakse konstruktoris vajalikud väljad ära
Objekti muutujaid saab teistes objekti meetodites kasutada
Konstruktor, objekti muutujad
class Student :
def __init__ (self, name, title ):
self.name = name
self.title = title
ago = Student("Ago" , "Sir" )
print (ago.name)
leela = Student("Leela" , "Captain" )
print (leela.title)
Konstruktori parameeter self
viitab loodavale objektile.
Parameetrid name
ja title
salvestatakse objekti muutujateks: self.name
ja self.title
Objekti muutujad
class Shop :
def __init__ (self, name, age, products_file=None ):
self.products = []
self.name = name
self.established = 2020 - age
if products_file is not None :
pass
def inventory (self ):
print (f"Inventory for {self.name} (est. {self.established} :" )
for p in self.products:
print ("product: .." )
Klass (class )
Defineerib andmetüübi
Šabloon, mida saab hiljem kasutada, et luua konkreetseid objekte (isendeid)
class Point2D :
"""Point in (x, y) coordinate space."""
def __init__ (self, x, y ):
self.x = x
self.y = y
def print_point (self ):
print (f"({self.x:.2 f} , {self.y:.2 f} )" )
Objekt (object )
Konkreetne isend, instants (instance )
Luuakse klassi kirjeldusest
Klassist võib luua lõpmata palju objekte
Samast klassist loodud objektid on sarnase struktuuriga (neil on samad meetodid ja muutujad)
Aga igal objektil on oma olek (muutujate väärtused)
p1 = Point2D(1.234 , 0.23456 )
p2 = Point2D(-1 , 3 )
p1.print_point()
p2.print_point()
Klass ja objekt
class Point2D :
"""Point in (x, y) coordinate space)."""
def __init__ (self, x, y ):
self.x = x
self.y = y
def print_point (self ):
print (f"({self.x:.2 f} , {self.y:.2 f} )" )
p1 = Point2D(1.234 , 0.23456 )
p2 = Point2D(-1 , 3 )
p1.print_point()
p2.print_point()
Objektide võrdlemine
p3 = Point2D(3 , 3 )
p4 = Point2D(3 , 3 )
p5 = p4
print (p3 == p4)
print (p4 == p5)
p3.x = 10
p3.print_point()
p4.x = 11
p4.print_point()
p5.print_point()
Erilised meetodid
Python võimaldab klassis ära kirjeldada objekti käitumist erinevates olukordades
Näiteks __eq__
meetodit kasutatakse selleks, et võrrelda objekte ==
võrdlusega
__str__
meetodit kasutatakse, et saada objektist sõne kuju
Lisaks näiteks __add__(self, other)
objektide liitmiseks jne
__lt__(self, other)
väikem-kui võrdluseks
__len__(self)
kui rakendatakse len(self)
Objektide võrdlus
Punkti puhul oleks mõistlik realiseerida objektide võrdlus väärtuste järgi
Kui kahel punktil on mõlemad koordinaadid samad, siis on ka objektid võrdsed.
class Point2D :
def __eq__ (self, other ):
if isinstance (other, Point2D):
return self.x == other.x and self.y == other.y
return False
__eq__
meetod käivitatakse võrdlemisel
Objektide võrdlus
p6 = Point2D(1 , 2 )
p7 = Point2D(1 , 2 )
print (p6 == p7)
print (p6 is p7)
p8 = p6
print (p6 is p8)
Võrdleme nüüd kahte objekti ==
võrdlusega. Tulemus on tõene, kuna käivitub __eq__
meetod, mis võrdleb sisu.
is
võrdlus kontrollib, kas viidatakse samale objektile
Objekt sõnena
__str__(self)
meetod võimaldab kirjeldada, mida objekti puhul sõnena tagastatakse
Näiteks printimisel kasutatakse seda
Samuti str(obj)
puhul.
Meetod tagastab sõne
Vaikimisi print(p1)
kuvab midagi sellist <__main__.Point2D object at 0x0050D5D0>
.
Objekt sõnena
class Point2D :
def __str__ (self ):
return f"({self.x:.2 f} , {self.y:.2 f} )"
p1 = Point2D(1 , 2 )
print (p1)
Objekt sõnena
Pythonis on eriline meetod __repr__
, mille eesmärk on tagastada üheselt mõistetav sõne.
Tihti tagastatakse sõne, millega saab objekti luua eval()
funktsiooni abil
Kui __str__
pole defineeritud, kutsutakse __repr__
välja.
__str__
meetodi eesmärk on pigem olla informatiivne
Seega alati on mõistlik kirjeldada __repr__
class Point2D :
def __repr__ (self ):
return f"Point2D({self.x} , {self.y} )"
Klassi muutujad
Klassi muutuja kirjeldatakse klassi sees väljaspool meetodeid
Klassi muutujal on üks väärtus läbi terve programmi
Sõltumata sellest, mitu objekti klassist luuakse, klassi muutujal on üks ühine väärtus
Üldiselt ei ole vaja kasutada
Klassi muutuja näide
class Doorbell :
click_count = 0
def __init__ (self ):
self.click_count = 0
def ring (self ):
print ("Ringing.." )
self.click_count += 1
Doorbell.click_count += 1
d1 = Doorbell()
d2 = Doorbell()
for _ in range (10 ): d1.ring()
for _ in range (4 ): d2.ring()
print (d1.click_count)
print (d2.click_count)
print (Doorbell.click_count)
Objekti väärtuste pärimine/muutmine
Kapseldamise eesmärk on peita objekti olek maailma eest ning lubada selle muutmine vaid läbi teatud meetodite.
Objekti väärtuste muutmiseks kasutatakse tavaliselt getter ja setter meetodeid
See annab võimaluse kontrollida, mida ja kuidas tagastatakse/muudetakse
class Student :
def __init__ (self, name ):
self.name = name
def set_name (self, name ):
self.name = name
def get_name (self ):
return self.name
@[1-8](`name` muutuja salvestatakse objekti muutujaks)
@[1-8](`age` muutuja kasutatakse `self.established` väärtuse arvutamiseks. Funktsiooni lõpus kaotab `age` kehtivuse.)
@[1-8](`products_file` on valikuline parameeter. Kui see on määratud, siis loetakse failist tooted.)
@[1-8](`self.products` luuakse siin tühja järjendina. Seal hakatakse hoidma kaupade nimekirja.)
@[1,9-13](`self` kaudu loodud muutujad on siin kättesaadavad: `name`, `established` ja `products`.)
@[1-8](Klassi kirjeldus)
@[3](`__init__` on eriline meetod, mis käivitatakse objekti loomisel.)
@[3](`self` on esimene parameeter ja viitab objektile.)
@[4,5,8](`self.x` ja `self.y` on objekti (isendi) muutujad.)
@[11-12](Loome kaks objekti `p1` ja `p2` erinevate väärtustega.)
@[11-15](Mõlemal objektil on oma olek. Ühe oleku muutumine ei mõjuta teist.)
@[1-3](Loome 2 isendit `p3` ja `p4`. `p5 = p4` tähistab seda, et `p5` viitab samale isendile kui `p4` )
@[1-5](Kuigi `p3` ja `p4` väärtused on samad, siis `==` võrdlusel kontrollitakse vaikimisi, kas kaks isendit on samad (viitavad samale objektile))
@[1-6](Kuna `p5` ja `p4` viitavad samale isendile, siis siin on tulemus tõene.)
@[1-9](Muudame `p3.x` väärtust, vaid sellel isendil muutub `x` väärtus.)
@[1-14](Muudame `p4.x` väärtust, `x` väärtus muutub nii `p4` kui `p5` jaoks. Miks?)
@[1-7](Konstruktor ja `print_point` meetodid on näitest välja jäätud)
@[4](Kirjeldame `__eq__` meetodi, mis käivitatakse objektide võrdlemisel)
@[4-7](`isinstance` kontrollib, kas `other` on üldse `Point2D` tüüpi. Kui ei ole, siis ei saa punkt ka `other` objektiga võrdne olla)
@[4-7](Kui `other` on `Point2D` tüüpi, siis võrreldakse `self` ja `other` objekti `x` ja `y` koordinaate.)