Шта је __инит__ у Питхон-у? [With Examples]

Želite li da započnete s objektno orijentisanim dizajnom u Pythonu? Napravite prve korake već danas tako što ćete se upoznati sa `__init__` metodom u Pythonu.

U ovom uputstvu, istražićemo osnove klasa i objekata u Pythonu, a zatim ćemo detaljno proučiti metodu `__init__`.

Nakon ovog tutorijala, moći ćete odgovoriti na sledeća pitanja:

  • Šta su to varijable instance ili atributi instance?
  • Kako metoda `__init__` pomaže u inicijalizaciji atributa instance?
  • Kako možemo podesiti podrazumevane vrednosti za atribute?
  • Kako možemo koristiti metode klase kao konstruktore za kreiranje objekata?

Krenimo!

Python Klase i Objekti

Klase su temeljne za objektno orijentisano programiranje u Pythonu. Možemo kreirati klasu i unutar nje definisati atribute i metode – kako bismo povezali podatke i funkcije koje rade s tim podacima.

Nakon što napravimo klasu, možemo je koristiti kao šablon za kreiranje objekata (instanci).

👩‍🏫 Primer! Hajde da kreiramo klasu `Zaposleni` gde će svaki objekat ove klase imati sledeće atribute:

  • `puno_ime`: puno ime zaposlenog u formatu ime prezime
  • `emp_id`: ID zaposlenog
  • `odeljenje`: odeljenje kojem pripada
  • `iskustvo`: broj godina iskustva

Šta to znači? 🤔

Svaki pojedinačni zaposleni biće instanca ili objekat klase `Zaposleni`. Svaki objekat imaće sopstvenu vrednost za `puno_ime`, `emp_id`, `odeljenje` i `iskustvo`.

Ovi atributi se takođe nazivaju varijable instance, a termine atributi i varijable instance koristićemo naizmenično.

Do dodavanja atributa doći ćemo malo kasnije. Za sada, kreiramo klasu `Zaposleni` ovako:

class Employee:
    pass

Korišćenje `pass` (kao čuvara mesta) pomaže nam da izbegnemo greške kada pokrenemo skriptu.

Iako trenutna verzija klase `Zaposleni` nije od velike koristi, ona je ipak validna klasa. Zato možemo kreirati objekte klase `Zaposleni`:

employee_1 = Employee()

print(employee_1)
#Output: <__main__.Employee object at 0x00FEE7F0>

Takođe možemo dodati atribute i inicijalizovati ih vrednostima kao što je prikazano:

employee_1.full_name="Amy Bell"
employee_1.department="HR"

Ali ovaj pristup dodavanju atributa instance je neefikasan i podložan greškama. Takođe, ne omogućava korišćenje klase kao šablona za kreiranje objekata. Tu metoda `__init__` stupa na scenu.

Razumevanje Uloge `__init__` Metode u Python Klasi

Trebalo bi da budemo u mogućnosti da inicijalizujemo varijable instance prilikom kreiranja objekta, a metoda `__init__` nam u tome pomaže. Metoda `__init__` se poziva svaki put kada se kreira novi objekat klase radi inicijalizacije vrednosti varijabli instance.

Ako ste programirali u jeziku kao što je C++, videćete da metoda `__init__` funkcioniše slično kao konstruktori.

Definisanje Metoda `__init__`

Dodajmo metodu `__init__` u klasu `Zaposleni`:

class Employee:
    def __init__(self, full_name,emp_id,department,experience):
        self.full_name = full_name
        self.emp_id = emp_id
        self.department = department
        self.experience = experience

Parametar `self` odnosi se na instancu klase, a `self.attribute` inicijalizuje atribut instance na vrednost sa desne strane.

Sada možemo kreirati objekte kao što je ovaj:

employee_2 = Employee('Bella Joy','M007','Marketing',3)
print(employee_2)
# Output: <__main__.Employee object at 0x017F88B0>

Kada ispišemo objekte zaposlenih, ne dobijamo nikakve korisne informacije osim klase kojoj pripadaju. Dodajmo metodu `__repr__` koja definiše niz za predstavljanje klase:

def __repr__(self):
        return f"{self.full_name},{self.emp_id} iz {self.department} sa {self.experience} godina iskustva."

Dodavanjem `__repr__` u klasu `Zaposleni`, imamo:

class Employee:
    def __init__(self, full_name,emp_id,department,experience):
        self.full_name = full_name
        self.emp_id = emp_id
        self.department = department
        self.experience = experience
    
     def __repr__(self):
        return f"{self.full_name},{self.emp_id} iz {self.department} sa {self.experience} godina iskustva."

Sada objekti zaposlenih imaju koristan niz za predstavljanje:

print(employee_2)
# Output: Bella Joy,M007 iz Marketinga sa 3 godina iskustva.

Nekoliko Konvencija

Pre nego što nastavimo dalje, evo nekoliko napomena:

  • Koristili smo `self` kao prvi parametar u metodi `__init__` za upućivanje na samu instancu klase i koristili `self.ime_atributa` za inicijalizaciju različitih atributa. Korišćenje `self` je preferirana konvencija (iako možete koristiti bilo koje drugo ime).
  • Kada definišemo metodu `__init__`, imena parametara u `__init__` definicijama podešavamo tako da odgovaraju imenima atributa. Ovo poboljšava čitljivost.

Kako Dodati Podrazumevane Vrednosti za Atribute

U primeru koji smo do sada kodirali, svi atributi su obavezni. To znači da je kreiranje objekta uspešno samo ako konstruktoru prosledimo vrednosti za sva polja.

Pokušajte da instancirate objekat klase `Zaposleni` bez prosleđivanja vrednosti za atribut `iskustvo`:

employee_3 = Employee('Jake Lee','E001','Engineering')

Dobićete sledeću grešku:

Traceback (most recent call last):
  File "main.py", line 22, in <module>
    employee_3 = Employee('Jake Lee','E001','Engineering')
TypeError: __init__() missing 1 required positional argument: 'experience'

Ali ako želite da određene atribute učinite opcionalnim, to možete uraditi tako što ćete obezbediti podrazumevane vrednosti za te atribute kada definišete metodu `__init__`.

Ovde dajemo podrazumevanu vrednost 0 za atribut `iskustvo`:

class Employee:
    def __init__(self, full_name,emp_id,department,experience=0):
        self.full_name = full_name
        self.emp_id = emp_id
        self.department = department
        self.experience = experience
    
     def __repr__(self):
        return f"{self.full_name},{self.emp_id} iz {self.department} sa {self.experience} godina iskustva."

Objekat `employee_3` je kreiran bez vrednosti za atribut `iskustvo`; podrazumevana vrednost 0 se koristi za iskustvo.

employee_3 = Employee('Jake Lee','E001','Engineering')
print(employee_3.experience)
# Output: 0

Alternativni Konstruktori Klasa Koji Koriste Metode Klase

Do sada smo videli samo kako da definišemo metodu `__init__` i postavimo podrazumevane vrednosti za atribute kada je to potrebno. Takođe znamo da treba da prosledimo vrednosti za tražene atribute u konstruktoru.

Ponekad, međutim, vrednosti za ove varijable instance (ili atribute) mogu biti dostupne u drugoj strukturi podataka, kao što je tuple, rečnik ili JSON string.

Pa šta da radimo?

Uzmimo primer. Pretpostavimo da imamo vrednosti varijable instance u Python rečniku:

dict_fanny = {'name':'Fanny Walker','id':'H203','dept':'HR','exp':2}

Možemo da pristupimo rečniku i dobijemo sve atribute ovako:

name = dict_fanny['name']
id = dict_fanny['id']
dept = dict_fanny['dept']
exp = dict_fanny['exp']

Nakon toga možete kreirati objekat tako što ćete proslediti ove vrednosti u konstruktor klase:

employee_4 = Employee(name, id, dept, exp)
print(employee_4)
# Output: Fanny Walker,H203 iz HR-a sa 2 godina iskustva.

Zapamtite: ovo morate da uradite za svaki novi objekat koji kreirate. Ovaj pristup je neefikasan i definitivno možemo bolje. Ali kako?

U Pythonu možemo koristiti metode klase kao konstruktore za kreiranje objekata klase. Za kreiranje metode klase koristimo dekorator `@classmethod`.

Hajde da definišemo metodu koja analizira rečnik, dobija vrednosti varijable instance i koristi ih za kreiranje objekata `Zaposleni`.

    @classmethod
    def from_dict(cls,data_dict):
        full_name = data_dict['name']
        emp_id = data_dict['id']
        department = data_dict['dept']
        experience = data_dict['exp']
        return cls(full_name, emp_id, department, experience)

Kada treba da kreiramo objekte koristeći podatke iz rečnika, možemo koristiti metodu klase `from_dict()`.

💡 Obratite pažnju na upotrebu `cls` u metodi klase umesto `self`. Baš kao što koristimo `self` za upućivanje na instancu, `cls` se koristi za upućivanje na klasu. Takođe, metode klase su vezane za klasu, a ne za objekte.

Dakle, kada pozovemo metodu klase `from_dict()` za kreiranje objekata, pozivamo je u klasi `Zaposleni`:

emp_dict = {'name':'Tia Bell','id':'S270','dept':'Sales','exp':3}
employee_5 = Employee.from_dict(emp_dict)
print(employee_5)
# Output: Tia Bell,S270 iz Prodaje sa 3 godina iskustva.

Sada, ako imamo rečnik za svakog od n zaposlenih, možemo koristiti metodu klase `from_dict()` kao konstruktor za instanciranje objekata – bez potrebe da preuzimamo vrednosti trenutne varijable iz rečnika.

📝Napomena o klasnim varijablama

Ovde smo definisali metodu klase koja je vezana za klasu, a ne za pojedinačne instance. Slično metodama klase, možemo imati i varijable klase.

Kao i metode klase, varijable klase su vezane za klasu, a ne za instancu. Kada atribut ima fiksnu vrednost za sve instance klase, možemo razmotriti da ih definišemo kao varijable klase.

Često Postavljana Pitanja

1. Zašto vam je potrebna metoda `__init__` u Pythonu?

Metoda `__init__` u definiciji klase omogućava nam da inicijalizujemo atribute ili varijable instance svih instanci klase. Metoda `__init__` se poziva svaki put kada se kreira nova instanca klase.

2. Možete li imati više metoda `__init__` u Python klasi?

Cilj postojanja više metoda `__init__` u Python klasi je da se obezbedi više konstruktora koji instanciraju objekte. Ali ne možete definisati više metoda `__init__`. Ako definišete više metoda `__init__`, druga i najnovija implementacija će zameniti prvu. Međutim, možete koristiti dekorator `@classmethod` da definišete metode klase koje se mogu koristiti kao konstruktori za instanciranje objekata.

3. Šta se dešava ako ne definišete metodu `__init__` u klasi?

Ako ne definišete metodu `__init__`, i dalje možete instancirati objekte. Međutim, moraćete ručno da dodate varijable instance i dodelite vrednosti svakoj od njih. Nećete moći da prosledite vrednosti za varijable instance u konstruktoru. Ovo ne samo da je sklono greškama, već i poništava svrhu postojanja klase kao nacrta iz kojeg možemo instancirati objekte.

4. Možete li imati podrazumevane vrednosti za argumente u metodi `__init__`?

Da, moguće je obezbediti podrazumevane vrednosti za jedan ili više atributa prilikom definisanja metode `__init__`. Pružanje podrazumevanih vrednosti pomaže da ti atributi budu opcionalni u konstruktoru. Atributi uzimaju podrazumevane vrednosti kada ne prosledimo vrednosti za te atribute u konstruktoru.

5. Možete li da izmenite atribute van metode `__init__`?

Da, uvek možete ažurirati vrednost atributa van metode `__init__`. Takođe možete dinamički dodati nove atribute instanci nakon što ste kreirali određenu instancu.

Zaključak

U ovom vodiču smo naučili kako da koristimo metodu `__init__` za inicijalizaciju vrednosti varijabli instance. Iako je ovo jednostavno, može biti ponavljajuće – posebno kada imate mnogo atributa.

Ako ste zainteresovani, možete istražiti modul klasa podataka. U Pythonu 3.7 i novijim verzijama, možete koristiti ugrađeni modul klasa podataka za kreiranje klasa podataka koje čuvaju podatke. Pored podrazumevanih implementacija `__init__` i drugih često korišćenih metoda, one dolaze sa mnogo sjajnih funkcija za nagoveštaje tipa, složene podrazumevane vrednosti i optimizaciju.

Zatim saznajte više o tome da li je `__name__` == `__main__` u Pythonu.