Python - Objekti i klase


Python objekti i klase

Python je objektno orijentisani programski jezik. Za razliku od procedura orijentiranog programiranja, gdje je glavni naglasak na funkcijama, objektno orijentirano programiranje naglašava objekte. Objekt je jednostavno zbirka podataka (varijable) i metoda (funkcija) koje djeluju na te podatke. Slično tome, klasa je nacrt za taj objekt.

O klasi možemo razmišljati kao o skici (prototipu) kuće. Sadrži sve detalje o podovima, vratima, prozorima itd. Na osnovu ovih opisa gradimo kuću. Kuća je objekt. Kako se mnoge kuće mogu napraviti iz nacrta kuće, možemo stvoriti mnoge predmete iz klase. Objekt se takođe naziva instancom klase, a postupak stvaranja ovog objekta naziva se instancijom (instantiation).



Definisanje klase u Pythonu

Kao što definicije funkcija počinju s ključnom riječi def u Pythonu, tako i definicije klase počinju s ključnom riječi class. Prvi string unutar klase naziva se docstring i ima kratki opis klase. Iako nije obavezno, ovo se preporučuje. Evo jednostavne definicije klase.

class MyNewClass:
    '''Ovo je docstring. Stvorio sam novu klasu'''
    pass

Klasa kreira novi lokalni prostor imena gdje su definisani svi njezini atributi. Atributi mogu biti podaci ili funkcije. U njemu postoje i posebni atributi koji započinju dvostrukim donjim crtama __. Na primjer, __doc__ nam daje docstring te klase.

Čim definišemo klasu, kreira se novi objekt klase s istim imenom. Ovaj objekt klase omogućava nam pristup različitim atributima, kao i instanciranje novih objekata te klase.

class Person:
    "Ovo je person klasa (class)"
    age = 10

    def greet(self):
        print('Pozdrav')


# Ispisuje: 10
print(Person.age)

# Ispisuje: <function Person.greet>
print(Person.greet)

# Ispisuje: 'Ovo je moja druga klasa (class)'
print(Person.__doc__)


Kreiranje objekta u Pythonu

Vidjeli smo da se objekt klase može koristiti za pristup različitim atributima. Takođe se može koristiti za stvaranje novih instanci objekta (instanciranje) te klase. Postupak za stvaranje objekta sličan je pozivu funkcije.

>>> harry = Person()

Ovo će stvoriti novu instancu objekta nazvanu harry. Atributima objekata možemo pristupiti pomoću prefiksa imena objekta. Atributi mogu biti podaci ili metoda. Metode objekta su odgovarajuće funkcije te klase. Budući da je Person.greet funkcijski objekt (atribut klase), Person.greet će biti objekt metode.

class Person:
    "Ovo je person klasa (class)"
    age = 10

    def greet(self):
        print('Pozdrav')


# stvaranje novog objekt klase Person
harry = Person()

# Ispisuje: <function Person.greet>
print(Person.greet)

# Ispisuje: <bound method Person.greet of <__main__.Person object>>
print(harry.greet)

# Pozivanje objekta greet() metode
# Ispisuje: Pozdrav
harry.greet()

Možda ste primijetili parametar self u definiciji funkcije unutar klase, ali metodu smo nazvali jednostavno kao harry.greet() bez ikakvih argumenata. I dalje je uspjelo. To je zato što, kad god objekt pozove svoju metodu, sam objekt se preda kao prvi argument. Dakle, harry.greet() prevodi se u Person.greet(harry).

Uopšteno, pozivanje metode s popisom od n argumenata ekvivalentno je pozivanju odgovarajuće funkcije s listom argumenata koja se kreira umetanjem objekta metode prije prvog argumenta. Iz tih razloga prvi argument funkcije u klasi mora biti sam objekt. To se uobičajeno naziva self. Može se nazvati i drugačije, ali toplo preporučujemo da se pridržavate konvencije. Sada ste upoznati s objektom klase, objektom instance, objektom funkcije, objektom metode i njihovim razlikama.



Konstruktori u Pythonu

Funkcije klase koje započinju dvostrukim donjim podvlačenjem __ nazivaju se posebnim funkcijama, jer imaju posebno značenje. Od posebnog interesa je funkcija __init__(). Ova posebna funkcija poziva se kad god se instancira novi objekt te klase. Ova vrsta funkcije naziva se i konstruktorima u objektno orijentiranom programiranju (OOP). Obično ga koristimo za inicijalizaciju svih varijabli.

class ComplexNumber:
    def __init__(self, r=0, i=0):
        self.real = r
        self.imag = i

    def get_data(self):
        print(f'{self.real}+{self.imag}j')


# Kreiranje novog ComplexNumber objekta
num1 = ComplexNumber(2, 3)

# Pozivanje get_data() metode
# Ispisuje: 2+3j
num1.get_data()

# Kreiranje drugog ComplexNumber objekta
# i kreiranje novg atributa 'attr'
num2 = ComplexNumber(5)
num2.attr = 10

# Ispisuje: (5, 0, 10)
print((num2.real, num2.imag, num2.attr))

# ali objekt c1 nema atribut 'attr'
# AttributeError: 'ComplexNumber' object has no attribute 'attr'
print(num1.attr)

U gornjem primjeru definisali smo novu klasu koja predstavlja složene brojeve. Ima dvije funkcije, __init__() za inicijalizaciju varijabli (zadane vrijednosti su nule) i get_data() za pravilan prikaz broja. Zanimljiva stvar koju treba primijetiti u gornjem koraku je da se atributi objekta mogu stvarati u hodu. Kreirali smo novi atribut attr za objekt num2 i pročitali ga takođe. Ali ovo ne stvara taj atribut za objekt num1.



Brisanje atributa i objekata

Bilo koji atribut objekta može se izbrisati bilo kada, koristeći del izraz. Isprobajte sljedeći primjer.

>>> num1 = ComplexNumber(2,3)
>>> del num1.imag
>>> num1.get_data()
Traceback (most recent call last):
...
AttributeError: 'ComplexNumber' object has no attribute 'imag'

>>> del ComplexNumber.get_data
>>> num1.get_data()
Traceback (most recent call last):
...
AttributeError: 'ComplexNumber' object has no attribute 'get_data'

Možemo čak i izbrisati sam objekt, koristeći del naredbu.

>>> c1 = ComplexNumber(1,3)
>>> del c1
>>> c1
Traceback (most recent call last):
...
NameError: name 'c1' is not defined

Zapravo je složenije od toga. Kada radimo c1 = ComplexNumber (1,3), u memoriji se kreira novi objekt instance i ime c1 se veže uz njega. Na naredbi del c1, ovo se vezanje uklanja, a ime c1 briše iz odgovarajućeg prostora imena. Objekt, međutim, nastavlja postojati u memoriji i ako za njega nije vezano nijedno drugo ime, kasnije se automatski uništava. Ovo automatsko uništavanje nereferenciranih objekata u Pythonu naziva se i sakupljanjem smeća (garbage collection).