Ce este __init__ în Python? [With Examples]

Îți dorești să te familiarizezi cu programarea orientată pe obiecte în Python? Fă primii pași acum, explorând metoda __init__ a limbajului Python.

În cadrul acestui ghid, vom parcurge conceptele fundamentale ale claselor și obiectelor în Python, continuând apoi cu studiul aprofundat al metodei __init__.

La finalul acestui material, vei fi capabil să dai răspunsuri la următoarele întrebări:

  • Ce reprezintă variabilele de instanță sau atributele de instanță?
  • Cum contribuie metoda init la configurarea inițială a atributelor de instanță?
  • Cum putem specifica valori prestabilite pentru atribute?
  • În ce mod putem utiliza metodele clasei ca mecanisme de construcție pentru a genera obiecte?

Să începem.

Clase și Obiecte în Python

Clasele sunt esențiale pentru programarea orientată pe obiecte în Python. Avem posibilitatea de a crea o clasă și de a defini caracteristici și acțiuni – pentru a uni datele și funcționalitățile corespunzătoare.

Odată ce am elaborat o clasă, o putem folosi drept model (sau schiță) pentru a crea obiecte (instanțe).

👩‍🏫 Un exemplu concret! Să alcătuim o clasă Employee, în care fiecare instanță a acestei clase are următoarele caracteristici:

  • nume_complet: numele complet al salariatului în formatul nume prenume
  • emp_id: identificatorul salariatului
  • departament: sectorul în care activează
  • experiență: numărul de ani de experiență acumulați

Ce semnifică toate acestea? 🤔

Fiecare salariat individual va fi o instanță sau un obiect al clasei Angajat. Și fiecare obiect va deține o valoare proprie pentru nume_complet, emp_id, departament și experiență.

Aceste caracteristici sunt denumite și variabile de instanță, iar termenii atribute și variabile de instanță vor fi folosiți interschimbabil.

Vom adăuga atribute în scurt timp. Pentru moment, să definim o clasă Angajat astfel:

class Employee:
    pass

Utilizarea lui pass (ca substitut) ne ajută să prevenim erorile când executăm scriptul.

Deși forma curentă a clasei Angajat nu este extrem de utilă, ea constituie totuși o clasă validă. Prin urmare, putem crea obiecte din clasa Angajat:

employee_1 = Employee()

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

De asemenea, putem adăuga caracteristici și le putem da valori, după cum se prezintă:

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

Însă, această metodă de a adăuga atribute de instanță este ineficientă și predispusă la erori. Mai mult, nu permite folosirea clasei ca model pentru a crea obiecte. Aici intervine metoda __init__.

Înțelegerea Importanței Metodei __init__ într-o Clasă Python

Ar trebui să avem posibilitatea de a seta valorile variabilelor de instanță la crearea unui obiect, iar metoda __init__ ne ajută să facem acest lucru. Metoda __init__ este apelată ori de câte ori se crează un nou obiect al clasei, cu scopul de a inițializa valorile variabilelor de instanță.

Dacă ai programat în limbaje precum C++, vei remarca că metoda __init__ are o funcție similară cu a constructorilor.

Definirea Metodei __init__

Să adăugăm metoda __init__ clasei Angajat:

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

Parametrul self se referă la instanța clasei, iar self.atribut inițializează atributul instanței cu valoarea din partea dreaptă.

Acum putem crea obiecte astfel:

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

Când tipărim obiectele angajat, nu primim informații relevante, cu excepția clasei de care aparțin. Să adăugăm o metodă __repr__ care definește un șir reprezentativ pentru clasă:

 def __repr__(self):
        return f"{self.full_name},{self.emp_id} from {self.department} with {self.experience} years of experience."

Prin adăugarea __repr__ la clasa Angajat, obținem:

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} from {self.department} with {self.experience} years of experience."

Acum obiectele angajat au un șir de reprezentare util:

print(employee_2)
# Output: Bella Joy,M007 from Marketing with 3 years of experience.

Câteva Convenții

Înainte de a continua, iată câteva aspecte importante:

  • Am folosit self ca prim parametru în metoda __init__ pentru a ne referi la instanța clasei și am utilizat self.nume_atribut pentru a inițializa diferitele caracteristici. Utilizarea lui self este convenția general acceptată (poți folosi și un alt nume).
  • Când definim metoda __init__, configurăm numele parametrilor din definițiile __init__ astfel încât să se potrivească cu numele atributelor. Acest lucru sporește lizibilitatea codului.

Cum Să Adaugi Valori Prestabilite pentru Caracteristici

În exemplul de până acum, toate atributele sunt obligatorii. Crearea corectă a obiectelor este posibilă doar dacă transferăm valori tuturor câmpurilor constructorului.

Încearcă să creezi o instanță a clasei Angajat fără a specifica valoarea pentru caracteristica experiență:

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

Vei primi următorul mesaj de eroare:

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'

Însă, dacă vrei să faci anumite atribute opționale, poți face acest lucru prin alocarea unor valori prestabilite pentru acele atribute când definești metoda __init__.

Aici, oferim o valoare implicită de 0 pentru caracteristica experiență:

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} from {self.department} with {self.experience} years of experience."

Obiectul employee_3 este generat fără valoarea pentru caracteristica experiență; valoarea prestabilită 0 este folosită pentru experiență.

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

Constructori Alternativi de Clas[ă Utilizând Metode de Clas[ă

Până în acest moment am văzut doar cum se definește metoda __init__ și cum se setează valorile prestabilite pentru atribute atunci când este necesar. Știm de asemenea că trebuie să transmitem valorile pentru caracteristicile obligatorii în constructor.

Uneori, totuși, valorile acestor variabile de instanță (sau atribute) pot fi disponibile într-o structură de date diferită, cum ar fi un tuplu, un dicționar sau un șir JSON.

Ce putem face într-o astfel de situație?

Să analizăm un exemplu. Să presupunem că avem valori ale variabilei de instanță într-un dicționar Python:

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

Putem accesa dicționarul și putem obține toate atributele astfel:

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

Ulterior, poți crea un obiect transmițând aceste valori constructorului clasei:

employee_4 = Employee(name, id, dept, exp)
print(employee_4)
# Output: Fanny Walker,H203 from HR with 2 years of experience.

Reține: trebuie să faci acest lucru pentru fiecare obiect nou pe care îl creezi. Această abordare este ineficientă și putem face cu siguranță ceva mai bun. Dar cum?

În Python, putem utiliza metodele clasei ca mecanisme de construire a obiectelor clasei. Pentru a crea o metodă de clasă, folosim decoratorul @classmethod.

Să definim o metodă care examinează dicționarul, obține valorile variabilei de instanță și le utilizează pentru a crea obiecte Angajat.

    @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)

Când este necesar să creăm obiecte utilizând datele dintr-un dicționar, putem folosi metoda clasei from_dict().

💡 Observă folosirea lui cls în metoda clasei, în loc de self. Așa cum folosim self pentru a ne referi la instanță, cls este folosit pentru a ne referi la clasă. De asemenea, metodele de clasă sunt legate de clasă și nu de obiecte.

Astfel, când apelăm metoda clasei from_dict() pentru a genera obiecte, o invocăm în clasa Angajat:

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 from Sales with 3 years of experience.

Acum, dacă avem un dicționar pentru fiecare dintre cei n salariați, putem utiliza metoda clasei from_dict() ca constructor pentru a crea instanțe în obiecte – fără să mai trebuiască să preluăm valorile variabilelor de instanță din dicționar.

📝O observație privind variabilele clasei

Aici am definit metoda clasei care este legată de clasă și nu de instanțe individuale. Similar metodelor de clasă, putem avea și variabile de clasă.

La fel ca metodele de clasă, variabilele de clasă sunt legate de clasă și nu de o instanță. Când o caracteristică are o valoare fixă pentru toate instanțele clasei, putem lua în considerare definirea acestora ca variabile de clasă.

Întrebări Frecvente

1. De ce este necesară metoda __init__ în Python?

Metoda __init__ dintr-o definiție de clasă ne dă posibilitatea să configurăm inițial caracteristicile sau variabilele de instanță ale tuturor instanțelor clasei. Metoda __init__ este apelată ori de câte ori se creează o nouă instanță a clasei.

2. Este permis să avem mai multe metode __init__ într-o clasă Python?

Scopul de a avea mai multe metode __init__ într-o clasă Python este de a furniza mai mulți constructori care inițiază obiecte. Dar nu poți defini mai multe metode __init__. Dacă definești mai multe metode __init__, a doua și cea mai recentă implementare o vor suprascrie pe prima. Cu toate acestea, poți utiliza decoratorul @classmethod pentru a defini metode de clasă care pot fi folosite ca mecanisme de construcție pentru a crea instanțe ale obiectelor.

3. Ce se întâmplă dacă nu specifici metoda __init__ într-o clasă?

Dacă nu definești metoda __init__, poți totuși să inițiezi obiecte. Totuși, va trebui să adaugi manual variabile de instanță și să atribui valori fiecăreia dintre ele. Nu vei putea transmite valorile variabilelor de instanță în constructor. Acest lucru nu este doar predispus la erori, dar și anulează scopul de a avea clasa ca un plan din care putem crea instanțe de obiecte.

4. Poți avea valori prestabilite pentru argumente în metoda __init__?

Da, este posibil să specifici valori implicite pentru unul sau mai multe atribute când definești metoda __init__. Furnizarea de valori implicite ajută la transformarea acestor atribute în opționale în cadrul constructorului. Atributele preiau valorile prestabilite atunci când nu transmitem valori pentru aceste atribute în constructor.

5. Este permisă modificarea caracteristicilor în afara metodei __init__?

Da, poți actualiza oricând valoarea unei caracteristici în afara metodei __init__. De asemenea, poți adăuga în mod dinamic atribute noi unei instanțe după ce ai creat-o.

Concluzie

În cadrul acestui tutorial, am învățat cum să folosim metoda __init__ pentru a inițializa valorile variabilelor de instanță. Deși acest lucru este simplu, poate deveni repetitiv, mai ales atunci când ai un număr mare de caracteristici.

Dacă ești interesat, poți explora modulul dataclasses. În Python 3.7 și versiunile ulterioare, poți utiliza modulul de clase de date încorporat pentru a crea clase de date care stochează date. Pe lângă implementările implicite ale __init__ și alte metode folosite frecvent, acestea vin cu multe caracteristici interesante pentru indicii de tip, valori implicite complexe și optimizare.

Apoi, descoperă mai multe informații despre dacă __name__==’__main__’ în Python.