Python je programski jezik koji podržava više paradigmi, a jedna od njih je objektno orijentisano programiranje (OOP). U srcu OOP-a nalaze se klase – moćni alati koji nam omogućavaju da organizujemo podatke i funkcionalnost u logične celine. U ovom članku ćemo detaljno istražiti koncept klasa u Python-u, od osnovnih do naprednih koncepata, uz mnogo primera koji će vam pomoći da solidno razumete ovu važnu temu.
Šta su klase i zašto su važne?
Klasa u programiranju predstavlja “nacrt” ili “šablon” za kreiranje objekata. Možete razmišljati o klasi kao o receptu za kolač – recept opisuje kako napraviti kolač, a svaki put kada pratite taj recept dobijate novi kolač (objekat) sa istim karakteristikama.
Klase omogućavaju:
- Enkapsulaciju – grupisanje podataka i funkcija koje rade sa tim podacima
- Nasleđivanje – kreiranje novih klasa baziranih na postojećim
- Polimorfizam – korišćenje istog interfejsa za različite tipove objekata
- Apstrakciju – sakrivanje kompleksnosti i prikazivanje samo neophodnih detalja
Osnovni koncept klasa u Python-u
Definisanje klase
Klasa se u Python-u definiše koristeći ključnu reč class
:
class Automobil:
"""Klasa koja predstavlja automobil."""
pass # Prazna klasa za sada
Kreiranje objekata (instanci) klase
Nakon definisanja klase, možemo kreirati objekte (instance) te klase:
moj_auto = Automobil() # Kreiranje nove instance klase Automobil
print(type(moj_auto)) # Output: <class '__main__.Automobil'>
Dodavanje atributa (varijabli) i metoda (funkcija)
Klase mogu imati atribute (varijable) i metode (funkcije). Hajde da dodamo neke osnovne atribute i metode našoj klasi Automobil
:
class Automobil:
"""Klasa koja predstavlja automobil."""
# Konstruktor - specijalna metoda koja se poziva pri kreiranju objekta
def __init__(self, marka, model, godina, boja):
self.marka = marka
self.model = model
self.godina = godina
self.boja = boja
self.brzina = 0 # Početna brzina
self.ukljucen = False
# Metoda za paljenje automobila
def upali(self):
if not self.ukljucen:
self.ukljucen = True
return f"{self.marka} {self.model} je upaljen!"
else:
return f"{self.marka} {self.model} je već upaljen!"
# Metoda za gašenje automobila
def ugasi(self):
if self.ukljucen:
self.ukljucen = False
self.brzina = 0
return f"{self.marka} {self.model} je ugašen."
else:
return f"{self.marka} {self.model} je već ugašen."
# Metoda za ubrzavanje
def ubrzaj(self, povecanje_brzine):
if self.ukljucen:
self.brzina += povecanje_brzine
return f"{self.marka} {self.model} sada ide {self.brzina} km/h."
else:
return f"Ne možete ubrzati, {self.marka} {self.model} nije upaljen!"
# Metoda za kočenje
def koci(self, smanjenje_brzine):
if self.ukljucen:
if smanjenje_brzine > self.brzina:
self.brzina = 0
else:
self.brzina -= smanjenje_brzine
return f"{self.marka} {self.model} sada ide {self.brzina} km/h."
else:
return f"Ne možete kočiti, {self.marka} {self.model} nije upaljen!"
Ova klasa definiše automobil sa nekoliko atributa (marka, model, godina, boja, brzina, ukljucen) i četiri metode (upali, ugasi, ubrzaj, koci).
Korišćenje klase
Sada kada smo definisali našu klasu, hajde da je koristimo:
# Kreiranje instance klase Automobil
moj_auto = Automobil("Toyota", "Corolla", 2020, "srebrna")
# Korišćenje atributa
print(f"Moj auto je {moj_auto.marka} {moj_auto.model} iz {moj_auto.godina}. godine, boje {moj_auto.boja}.")
# Korišćenje metoda
print(moj_auto.upali())
print(moj_auto.ubrzaj(50))
print(moj_auto.koci(20))
print(moj_auto.ugasi())
Output:
Moj auto je Toyota Corolla iz 2020. godine, boje srebrna.
Toyota Corolla je upaljen!
Toyota Corolla sada ide 50 km/h.
Toyota Corolla sada ide 30 km/h.
Toyota Corolla je ugašen.
Važni koncepti klasa
self parametar
U Python-u, self
parametar je referenca na trenutnu instancu klase i koristi se za pristup varijablama i metodama te instance. self
je sam po sebi samo konvencija – možete ga nazvati kako god želite, ali dobra praksa je koristiti standardni naziv self
.
Konstruktor (init)
Metoda __init__
je specijalna metoda u Python-u koja se automatski poziva kada se kreira nova instanca klase. Može se koristiti za inicijalizaciju atributa objekta:
def __init__(self, marka, model, godina, boja):
self.marka = marka
self.model = model
self.godina = godina
self.boja = boja
Klasa vs. Instanca atributa
Python razlikuje atribute klase i atribute instance:
class Automobil:
# Atribut klase - zajednički za sve instance
broj_tockova = 4
def __init__(self, marka, model):
# Atributi instance - jedinstveni za svaku instancu
self.marka = marka
self.model = model
Atributi klase su zajednički za sve instance te klase, dok su atributi instance jedinstveni za svaku instancu:
auto1 = Automobil("Toyota", "Corolla")
auto2 = Automobil("Honda", "Civic")
print(auto1.broj_tockova) # Output: 4
print(auto2.broj_tockova) # Output: 4
# Promena atributa klase utiče na sve instance
Automobil.broj_tockova = 6
print(auto1.broj_tockova) # Output: 6
print(auto2.broj_tockova) # Output: 6
# Promena atributa instance utiče samo na tu instancu
auto1.marka = "Mazda"
print(auto1.marka) # Output: Mazda
print(auto2.marka) # Output: Honda (nepromenjeno)
Privatni atributi i metode
Python nema pravi koncept privatnih atributa ili metoda, ali konvencija je da se koristi jedanunderscores (_
) ili dva underscores (__
) kao prefiks za “privatne” atribute ili metode:
class Automobil:
def __init__(self, marka, model):
self.marka = marka # Javni atribut
self._model = model # "Privatni" atribut (konvencija)
self.__godina = 2022 # "Jako privatni" atribut (name mangling)
def _privatna_metoda(self): # "Privatna" metoda
return "Ovo je privatna metoda."
def __jako_privatna_metoda(self): # "Jako privatna" metoda
return "Ovo je jako privatna metoda."
Kada koristite dvostruki underscore (__
), Python interno menja ime (name mangling) da bi sprečio slučajno prepisivanje u podklasama:
moj_auto = Automobil("Toyota", "Corolla")
print(moj_auto.marka) # Output: Toyota
print(moj_auto._model) # Output: Corolla
# print(moj_auto.__godina) # Greška: AttributeError
print(moj_auto._Automobil__godina) # Output: 2022 (mangled name)
Nasleđivanje
Nasleđivanje je jedan od ključnih koncepata OOP-a, koji omogućava kreiranje nove klase koja nasleđuje atribute i metode postojeće klase:
class Vozilo:
def __init__(self, marka, model, godina):
self.marka = marka
self.model = model
self.godina = godina
self.ukljucen = False
def upali(self):
self.ukljucen = True
return f"{self.marka} {self.model} je upaljen!"
def ugasi(self):
self.ukljucen = False
return f"{self.marka} {self.model} je ugašen."
def opis(self):
return f"Vozilo: {self.marka} {self.model} ({self.godina})"
# Automobil nasleđuje Vozilo
class Automobil(Vozilo):
def __init__(self, marka, model, godina, broj_vrata):
# Poziv konstruktora roditeljske klase
super().__init__(marka, model, godina)
self.broj_vrata = broj_vrata
self.brzina = 0
def ubrzaj(self, povecanje_brzine):
if self.ukljucen:
self.brzina += povecanje_brzine
return f"{self.marka} {self.model} sada ide {self.brzina} km/h."
else:
return f"Ne možete ubrzati, {self.marka} {self.model} nije upaljen!"
# Prepisivanje metode opis iz roditelske klase
def opis(self):
return f"Automobil: {self.marka} {self.model} ({self.godina}) sa {self.broj_vrata} vrata"
# Kamion takođe nasleđuje Vozilo
class Kamion(Vozilo):
def __init__(self, marka, model, godina, nosivost):
super().__init__(marka, model, godina)
self.nosivost = nosivost
def opis(self):
return f"Kamion: {self.marka} {self.model} ({self.godina}) nosivosti {self.nosivost} tona"
Sada možemo koristiti ove klase:
# Kreiranje instanci
vozilo = Vozilo("Generic", "Vehicle", 2020)
auto = Automobil("Toyota", "Corolla", 2020, 4)
kamion = Kamion("Volvo", "FH16", 2021, 20)
# Pozivanje metoda
print(vozilo.opis()) # Output: Vozilo: Generic Vehicle (2020)
print(auto.opis()) # Output: Automobil: Toyota Corolla (2020) sa 4 vrata
print(kamion.opis()) # Output: Kamion: Volvo FH16 (2021) nosivosti 20 tona
# Korišćenje nasleđenih metoda
print(auto.upali()) # Output: Toyota Corolla je upaljen!
print(auto.ubrzaj(50)) # Output: Toyota Corolla sada ide 50 km/h.
Višestruko nasleđivanje
Python podržava višestruko nasleđivanje, gde klasa može da nasledi više roditeljskih klasa:
class Elektricno:
def __init__(self, baterija_kapacitet):
self.baterija_kapacitet = baterija_kapacitet
self.baterija_nivo = 100
def napuni(self):
self.baterija_nivo = 100
return "Baterija je napunjena 100%!"
def koristi_struju(self, kolicina):
if self.baterija_nivo >= kolicina:
self.baterija_nivo -= kolicina
return f"Preostalo baterije: {self.baterija_nivo}%"
else:
return "Nedovoljno baterije!"
# Električni automobil nasleđuje i Automobil i Elektricno
class ElektricniAutomobil(Automobil, Elektricno):
def __init__(self, marka, model, godina, broj_vrata, baterija_kapacitet):
Automobil.__init__(self, marka, model, godina, broj_vrata)
Elektricno.__init__(self, baterija_kapacitet)
def ubrzaj(self, povecanje_brzine):
# Električi automobil troši bateriju pri ubrzavanju
potrosnja = povecanje_brzine / 10
status_baterije = self.koristi_struju(potrosnja)
if "Nedovoljno" not in status_baterije:
self.brzina += povecanje_brzine
return f"{self.marka} {self.model} sada ide {self.brzina} km/h. {status_baterije}"
else:
return f"Ne možete ubrzati, {status_baterije}"
def opis(self):
return f"Električni automobil: {self.marka} {self.model} ({self.godina}) sa kapacitetom baterije {self.baterija_kapacitet} kWh"
Sada možemo koristiti elektični automobil:
tesla = ElektricniAutomobil("Tesla", "Model 3", 2022, 4, 75)
print(tesla.opis())
print(tesla.upali())
print(tesla.ubrzaj(50)) # Troši 5% baterije
print(tesla.ubrzaj(100)) # Troši 10% baterije
print(tesla.napuni())
Output:
Električni automobil: Tesla Model 3 (2022) sa kapacitetom baterije 75 kWh
Tesla Model 3 je upaljen!
Tesla Model 3 sada ide 50 km/h. Preostalo baterije: 95%
Tesla Model 3 sada ide 150 km/h. Preostalo baterije: 85%
Baterija je napunjena 100%!
Specijalne (magične) metode
Python klase mogu implementirati specijalne metode (često zvane “magične metode” ili “dunder metode” zbog dvostrukih underscores) koje omogućavaju instancama da podržavaju razne Python operacije:
class Tacka:
def __init__(self, x, y):
self.x = x
self.y = y
# Omogućava korišćenje str() funkcije
def __str__(self):
return f"({self.x}, {self.y})"
# Omogućava korišćenje repr() funkcije
def __repr__(self):
return f"Tacka({self.x}, {self.y})"
# Omogućava korišćenje + operatora
def __add__(self, other):
if isinstance(other, Tacka):
return Tacka(self.x + other.x, self.y + other.y)
else:
raise TypeError("Možete sabirati samo sa drugom Tackom!")
# Omogućava korišćenje == operatora
def __eq__(self, other):
if isinstance(other, Tacka):
return self.x == other.x and self.y == other.y
return False
# Omogućava korišćenje len() funkcije
def __len__(self):
# Dužina vektora od (0,0) do tačke, zaokružena na ceo broj
import math
return int(math.sqrt(self.x ** 2 + self.y ** 2))
Korišćenje ovih metoda:
t1 = Tacka(3, 4)
t2 = Tacka(1, 2)
print(t1) # Output: (3, 4) - koristi __str__
print(repr(t1)) # Output: Tacka(3, 4) - koristi __repr__
print(t1 + t2) # Output: (4, 6) - koristi __add__
print(t1 == t2) # Output: False - koristi __eq__
print(len(t1)) # Output: 5 - koristi __len__ (dužina vektora od (0,0) do (3,4))
Klasne i statičke metode
Klasne metode
Klasne metode su metode koje se pozivaju na klasi, a ne na instanci klase. Deklarišu se pomoću @classmethod
dekoratora i primaju cls
kao prvi parametar umesto self
:
class Automobil:
broj_kreiranih = 0
def __init__(self, marka, model):
self.marka = marka
self.model = model
Automobil.broj_kreiranih += 1
@classmethod
def broj_automobila(cls):
return f"Ukupno je kreirano {cls.broj_kreiranih} automobila."
@classmethod
def kreiraj_iz_stringa(cls, auto_string):
marka, model = auto_string.split('-')
return cls(marka, model)
Korišćenje klasnih metoda:
# Korišćenje običnog konstruktora
auto1 = Automobil("Toyota", "Corolla")
auto2 = Automobil("Honda", "Civic")
# Pozivanje klasne metode
print(Automobil.broj_automobila()) # Output: Ukupno je kreirano 2 automobila.
# Korišćenje alternativnog konstruktora
auto3 = Automobil.kreiraj_iz_stringa("Mazda-CX5")
print(f"{auto3.marka} {auto3.model}") # Output: Mazda CX5
print(Automobil.broj_automobila()) # Output: Ukupno je kreirano 3 automobila.
Statičke metode
Statičke metode su metode koje ne zahtevaju pristup ni instanci ni klasi. Deklarišu se pomoću @staticmethod
dekoratora:
class MatematikaUtil:
@staticmethod
def saberi(a, b):
return a + b
@staticmethod
def oduzmi(a, b):
return a - b
@staticmethod
def je_prost_broj(broj):
if broj < 2:
return False
for i in range(2, int(broj ** 0.5) + 1):
if broj % i == 0:
return False
return True
Korišćenje statičkih metoda:
# Nije potrebno kreirati instancu
print(MatematikaUtil.saberi(5, 3)) # Output: 8
print(MatematikaUtil.oduzmi(10, 7)) # Output: 3
print(MatematikaUtil.je_prost_broj(17)) # Output: True
print(MatematikaUtil.je_prost_broj(20)) # Output: False
Apstraktne klase
Apstraktne klase su klase koje ne mogu biti direktno instancirane i služe kao šabloni za druge klase. Za definisanje apstraktnih klasa u Python-u koristimo abc
modul:
from abc import ABC, abstractmethod
class Oblik(ABC):
@abstractmethod
def povrsina(self):
pass
@abstractmethod
def obim(self):
pass
def opis(self):
return "Ovo je geometrijski oblik."
class Pravougaonik(Oblik):
def __init__(self, sirina, visina):
self.sirina = sirina
self.visina = visina
def povrsina(self):
return self.sirina * self.visina
def obim(self):
return 2 * (self.sirina + self.visina)
class Krug(Oblik):
def __init__(self, poluprecnik):
self.poluprecnik = poluprecnik
def povrsina(self):
import math
return math.pi * (self.poluprecnik ** 2)
def obim(self):
import math
return 2 * math.pi * self.poluprecnik
Korišćenje ovih klasa:
# Ne možemo direktno instancirati apstraktnu klasu
# oblik = Oblik() # Ovo će baciti TypeError
# Ali možemo instancirati njene podklase
pravougaonik = Pravougaonik(5, 4)
krug = Krug(3)
print(f"Površina pravougaonika: {pravougaonik.povrsina()}") # Output: 20
print(f"Obim pravougaonika: {pravougaonik.obim()}") # Output: 18
print(f"Opis pravougaonika: {pravougaonik.opis()}") # Output: Ovo je geometrijski oblik.
print(f"Površina kruga: {krug.povrsina():.2f}") # Output: ~28.27
print(f"Obim kruga: {krug.obim():.2f}") # Output: ~18.85
Zaključak
Klase su srce objektno orijentisanog programiranja u Python-u i pružaju moćan način za organizaciju podataka i funkcionalnosti. U ovom članku smo prošli kroz osnovne koncepte klasa kao što su definisanje klase, kreiranje objekata, atributi i metode, kao i naprednije koncepte poput nasleđivanja, višestrukog nasleđivanja, specijalnih metoda, klasnih i statičkih metoda i apstraktnih klasa.
Razumevanje i pravilna primena ovih koncepata će vam pomoći da pišete bolje organizovan, modularniji i lakše održiv kod. Kao i uvek, najbolji način da savladate ove koncepte je praksa – pokušajte da primenite ono što ste naučili u vašim Python projektima!
U budućim člancima ćemo dublje istraživati napredne teme vezane za klase kao što su deskriptori, meta klase, i obrasci dizajna koji koriste klase za rešavanje složenih problema.
Predhodna lekcija: funkcije u pythonu