Knyga/Klasės
Klasės
Pitonas yra objektinė programavimo kalba, tad, iš principo, viskas, kas naudojama pitone yra objektas, su visais jam priklausančiais kitamaisiais bei metodais. Klasė yra tarsi brėžinys/maketas (angliškai - blueprint), pagal kurį yra kuriami objektai. Klasėse yra apibrėžiama objekto struktūra (kintamieji) ir jo funkcionalumas (angliškai - behaviour). Klasės inkapsuliuoja duomenis ir funkcionalumus, skatina kodo pernaudojamumą ir moduliškumą.
Inkapsuliacija – tai vienas iš pagrindinių objektinio programavimo principų ir viena svarbiausių klasės užduočių. Programavime inkapsuliacija suprantama, kaip tiesioginės prieigos prie tam tikrų duomenų ar metodų apribojimas. Paprastai pasakius, tai reiškia, kad tam tikra informacija ar funkcionalumas nėra prieinamas vartotojui, naudojančiam objektą, pavyzdžiui, apribojama vartotojo teisė matyti/keisti objekto ID kintamąjį, sukūrimo laiką, ir pan. Inkapsuliacijos naudojimas yra itin svarbus, kai yra siekiama apsaugoti tam tikrus jautrius duomenis nuo pakeitimų.
Atkreipikime dėmesį į tai, kad yra naudojamas naujas terminas – metodas. Metodu vadiname funkciją, kai ji priklauso kokiai nors klasei. Tai yra nuo seno įsišaknijęs terminas, leidžiantis atskirti, kam priklauso funkcija – ar ji yra taikoma pati savaime, ar priklauso klasei/objektui.
Klasės struktūra
Kiekviena klasė pitone prasideda nuo raktažodžio class. Kode klasės deklaravimas atrodo taip:
class MyClass
Susipažinome su klasės deklaravimu, bet kas sudaro pačią klasę? Klasė susideda iš jai priklausančių kintamųjų ir metodų. Iš esmės kiekviena klasė turės savo kintamuosius ir metodus, kadangi tuščia klasė (išskyrus tam tikrus specifinius atvejus) iš esmės neturi jokios prasmės ir neatlieka savo pagrindinės funkcijos – skatinti kodo pernaudojamumą bei moduliškumą. Tikra klasė turėtų atrodyti maždaug taip:
class Žmogus:
vardas = None
amžius = None
def pakeisti_vardą(self, naujas_vardas):
self.vardas= naujas_vardas
Kaip matome, yra deklaruota klasė Žmogus, ji turi du kintamuosius vardas ir amžius bei metodą pakeisti_vardą(), kuris kaip parametrą (naujas_vardas) priima tekstinę eilutę su vardu ir juo pakeičia klasės kintamąjį vardas. Viskas kas yra aprašyta po klasės deklaracija, priklauso klasei, nesvarbu, ar tai būtų kintamieji, ar metodai.
Objekto sukūrimas
Kiekviena klasė turi specialų metodą, pavadinimu konstruktorius (angliškai - constructor), kurio paskirtis – kurti objektus, atitinkančios tos klasės struktūrą, priskirti jo kintamiesiems vertes. Jis visada iškviečiamas kaip metodas su klasės pavadinimu - klasėsPavadinimas(). Konstruktorius yra dviejų rūšių - numatytasis ir deklaruotas.
Numatytasis konstruktorius – tai konstruktorius, kurį kiekvienai klasei suteikia pats pitonas, jeigu programuotojas nedeklaruoja kitokio konstruktoriaus. Pagrindinė šio konstruktoriaus paskirtis – sukurti objektą, tačiau jis neatlieka jokių kitų veiksmų - nepriskiria jokių kintamųjų verčių, jų neapdoroja ir pan. Tai reiškia, kad tuo atveju, jeigu klasės kintamieji neturi priskirtų verčių, tai ir sukurto objekto kintamieji tų verčių neturės. Pavyzdžiui turime klasę:
class Žmogus:
vardas = None
amžius = NoneKaip matome, kintamieji neturi jokios reikšmės, tą indikuoja raktažodis None. Norint šios klasės pagrindu sukurti objektą, mes turime iškviesti numatytąjį konstruktorių:
Jonas = Žmogus()
Tokiu būdu sukuriamas Žmogus tipo objektas ir priskiriamas kintamajam Jonas. Objektas Jonas turi visus klasės kintamuosius, t. y. Jonas turi vardas ir amžius, bei jų abiejų reikšmės turėtų sutapti su klasėje nurodytomis reikšmėmis. Tą patikrinti galime tokiu būdu:
class Žmogus:
vardas = None
amžius = 24
Jonas = Žmogus()
Print(f“Vardas: {Jonas.Vardas}”)
Print(f"Amžius: {Jonas.Amžius}")
Šis kodas į terminalą išves dvi eilutes:
“Vardas: None”
“Amžius: 24”
Taigi, matome, kad objektas Jonas turi tuos pačius kintamuosius ir reikšmes, kokios yra priskirtos kintamiesiems klasėje.
Deklaruotasis konstruktorius – tai yra konstruktorius, kuris yra aprašomas programuotojo. Priešingai negu numatytasis konstruktorius, šis konstruktorius gali atlikti papildomus veiksmus kuriant objektą, pavyzdžiui, užpildo objekto kintamuosius duomenimis, atlieka papildomus veiksmus (išspausdina kintamųjų reikšmes, iškviečia reikalingus metodus, sukuria papildomus objektus ir pan.). Tokio tipo konstruktorius kode yra deklaruojamas pavadinimu __init__(), o per jo parametrus nurodome, kokias reikšmes šis konstruktorius priima ir jas priskiria kuriamo objekto kintamiesiems:
class Žmogus:
vardas = None
amžius = 24
def __init__(self, vardas, amžius):
self.vardas = vardas
self.amžius = amžius
Jonas = Žmogus()
Print(f“Vardas: {Jonas.Vardas}”)
Print(f"Amžius: {Jonas.Amžius}")Kaip matome, konstruktorius reikalauja dviejų parametrų - vardas ir amžius. Jis taip pat turi specialų self parametrą, bet jo paduoti konstruktoriui nereikia, jis leidžia konstruktoriui pasiekti objekto kintamuosius ir metodus prieš priskiriant objektą kintamajam. Kurdami objektą Jonas, konstruktoriui mes paduodame tekstinę eilutę su vardu “Jonas” bei skaičių “14”. Kodo vykdymo pabaigoje bus išspausdintos objekto Jonas kintamųjų vardas ir amžius vertės - “Vardas: Jonas” ir “Amžius: 14”. Taigi, deklaruotasis konstruktorius, priešingai negu numatytasis, sukūrė objektą su programuotojo numatytomis kintamųjų reikšmėmis. Deklaruotasis konstruktorius gali turėti faktiškai neribotą kiekį parametrų, kuriuos gali priimti ir priskirti objekto kintamiesiems, tačiau vadovaujantis gerosiomis programavimo praktikomis, konstruktorius neturėtų priimti daugiau kaip penkis parametrus. Paminėtina ir tai, kad konstruktoriuje galima nurodyti numatytąsias reikšmes kintamiesiems, kurios bus priskirtos, jeigu programuotojas nepaduoda jokių parametrų, kviesdamas deklaruotąjį konstruktorių:
class Žmogus:
vardas = None
amžius = 24
def __init__(self, vardas="Bevardis", amžius=0):
self.vardas = vardas
self.amžius = amžius
Jonas = Žmogus()
Print(f“Vardas: {Jonas.Vardas}”)
Print(f"Amžius: {Jonas.Amžius}")Kode aprašytas konstruktorius reikalauja dviejų parametrų - vardas ir amžius, bet abu parametrai turi priskirtą numatytąją reikšmę - "Bevardis" ir 0. Tą indikuoja lygybės ženklas ir pageidaujama tekstinė eilutė (parametro vardas atveju) ir skaičius (parametro amžius atveju). Kodo vykdymo pabaigoje bus išspausdintos objekto Jonas kintamųjų Vardas ir Amžius vertės - “Vardas: Bevardis” ir “Amžius: 0”. Kadangi deklaruotasis konstruktrius negavo jokių parametrų, jis kintamiesiems priskyrė konstruktoriuje nurodytas numatytąsias vertes.
Klasės metodų naudojimas
Kaip jau minėta anksčiau, klasės gali turėti savo metodus. Metodai taip pat yra pasiekiami objekto, ir gali būti naudojami:
class Žmogus:
vardas = None
amžius = 24
def pakeisti_vardą(self, naujas_vardas):
self.vardas = naujas_vardas
Jonas = Žmogus()
Print(f“Vardas iki pakeitimo: {Jonas.Vardas}”)
Jonas.pakeisti_vardą(“Jonas”)
Print(f“Vardas po pakeitimo: {Jonas.Vardas}”)Šis kodas taip pat išves dvi eilutes, vardo reikšmę prieš pakeisti_vardą () metodo kvietimą, ir po jo:
“Vardas iki pakeitimo: None”
“Vardas po pakeitimo: Jonas”
Svarbu paminėti tai, kad vardas yra pakeičiamas tik objekto “Jonas” kontekste, t. y., jeigu turėsime objektą “Petras”, objekto Jonas iškviesta funkcija pakeisti_vardą(“Jonas”), ji nepakeis kintamojo Vardas objekte Petras. Pažiūrėkime, kaip tai atrodo kode:
class Žmogus:
vardas = None
amžius = None
def pakeisti_vardą(self, naujas_vardas):
self.vardas = naujas_vardas
Jonas = Žmogus()
Petras = Žmogus()
Print(f“Objekto Jonas vardas iki pakeitimo: {Jonas.vardas}”)
Print(f“Objekto Petras vardas iki pakeitimo: {Petras.vardas}”)
Jonas.pakeisti_vardą(“Jonas”)
Print(f“Objekto Jonas vardas po pakeitimo: {Jonas.vardas}”)
Print(f“Objekto Petras vardas po pakeitimo: {Petras.vardas}”)
Šis kodas išves keturias eilutes, abiejų objektų kintamojo Vardas reikšmę prieš pakeisti_vardą() metodo kvietimą, ir po jo:
“Objekto Jonas vardas iki pakeitimo: None”
“Objekto Petras vardas iki pakeitimo: None”
“Objekto Jonas vardas po pakeitimo: Jonas”
“Objekto Petras vardas po pakeitimo: None”
Kaip matome, objektui Petras priklausantis kintamasis vardas nebuvo pakeistas, nors mes ir pakeitėme kintamojo vardas reikšmę objekte Jonas. Taip pasireiškia viena iš pagrindinių objekto savybių - kiekvienas objektas turi savo kintamuosius ir jų reikšmės yra atskirtos nuo kitų, tos pačios klasės pagrindu sukurtų objektų. Yra tam tikrų šios taisyklės išimčių, bet jas paklabėsime kitose temose.