Introducere in Python - Partea a IV-a. Clase si obiecte
14.09.2009
Programarea in general se bazeaza foarte mult pe reutilizarea codului. De obicei, aceasta se realizeaza cu ajutorul functiilor. Daca ai scris deja un cod ce indeplineste o anumita sarcina, atunci il poti executa de oricate ori vrei daca il incluzi intr-o functie. In plus, o functie poate fi apelata de oriunde din cod si computerul va sti intotdeauna la ce te referi.
17681 afisari 1 Rating (0 voturi) 30 min

Introducere

Programarea in general se bazeaza foarte mult pe reutilizarea codului. De obicei, aceasta se realizeaza cu ajutorul functiilor. Daca ai scris deja un cod ce indeplineste o anumita sarcina, atunci il poti executa de oricate ori vrei daca il incluzi intr-o functie. In plus, o functie poate fi apelata de oriunde din cod si computerul va sti intotdeauna la ce te referi.

Desigur, functiile isi au limitele lor. Ele nu stocheaza informatii cum ar valorile variabilelor, ceea ce inseamna ca de fiecare data cand este rulata, o functie incepe de la zero. Atunci, ce se intampla daca anumite functii si variabile se afla in stransa legatura si trebuie sa interactioneze destul de mult?

Obiectele din lumea reala au doua caracteristici: stare si comportament. Cainii au stare (nume, culoare, rasa, le este foame) si comportament (latra, alearga, dau din coada). Si bicicletele au stare (trepte de viteza, cadenta a pedalei, frane) si comportament (schimbarea vitezei, schimbarea cadentei pedalei, aplicarea franei).

Comportamentul unui obiect poate fi modelat cu usurinta cu ajutorul functiilor. Dar ce se intampla atunci cand vrei sa retii starea unui obiect? Ce se intampla daca de fiecare data cand te plimbi cu bicicleta, lantul slabeste, materialul de pe sa se uzeaza cate putin, devii din ce in ce mai frustrat si apare o noua zgarietura pe ghidon? O functie nu poate face asta. O functie conduce la un singur rezultat, nu la patru, cinci sau cinci sute. Avem nevoie de o modalitate de grupare a functiilor si a variabilelor intr-un singur loc, pentru a putea interactiona intre ele.

Identificarea starii si a comportamentului in cazul obiectelor reale reprezinta o metoda minunata de a incepe sa gandesti in termenii programarii orientate pe obiecte. Obiectele software sunt din punct de vedere conceptual similare obiectelor lumii reale: si acestea au stare si comportament. Un obiect isi pastreaza starea in campuri (variabile in anumite limbaje de programare) si isi expun comportamentul prin metode (functii in anumite limbaje de programare). Metodele opereaza asupra starii interne a unui obiect si servesc ca mecanism primar in cazul comunicarii de la obiect la obiect. Ascunderea starii interne si solicitarea ca orice interactiune sa se execute prin intermediul metodelor obiectelor poarta numele de incapsulare a datelor - principiul fundamental al programarii orientate pe obiecte.

Crearea unei clase

In lumea reala, deseori vei gasi multe obiecte individuale de acelasi fel. Pot exista mii de alte biciclete, toate avand aceleasi caracteristici, fiind acelasi model. Fiecare bicicleta a fost construita dupa acelasi tipar, deci contine aceleasi componente. In termenii programarii orientate pe obiecte, spunem ca bicicleta este o instanta a clasei de obiecte cunoscute sub numele de biciclete. Deci, o clasa reprezinta tiparul dupa care sunt create obiectele individuale, ce poarta numele de instante ale clasei.

Deci cum definesti o clasa? In primul rand, declaratia unei clase trebuie sa inceapa cu operatorul class:

 
# Definitia unei clase
class nume_clasa:
    [instructiune 1]
    [instructiune 2]
    [instructiune 3]
    [etc]

Mai jos poti vedea un exemplu de cod ce defineste o clasa FormaGeometrica:

 
#Exemplu de clasa
class FormaGeometrica:
    def __init__(self,x,y):
        self.x = x
        self.y = y
    descriere = "Aceasta forma nu a fost descrisa inca"
    autor = "Nu exista un autor al acestei forme "
    def aria(self):
        return self.x * self.y
    def perimetrul(self):
        return 2 * self.x + 2 * self.y
    def seteazaDescriere(self,text):
        self.descriere = text
    def seteazaAutor(self,text):
        self.autor = text
    def scaleaza(self,scale):
        self.x = self.x * scale
        self.y = self.y * scale

Dupa cum poti vedea, clasa Shape contine o descriere a unei forme geometrice (data de variabile) si operatiunile pe care le poti efectua cu forma (date de functii). Acesta este un aspect foarte important - nu ai creat de fapt o forma, ci descrierea unei forme. Forma are o latime (x), o inaltime (y) si metode cu ajutorul caruia ii poti calcula aria si perimetrul.

Ceea ce trebuie sa retii este ca definirea unei clase nu ruleaza nici un cod, ci are rolul de a grupa functii si variabile intr-o singura entitate.

Functia denumita __init__ este apelata cand cream o instanta a clasei FormaGeometrica - adica, atunci cand cream o forma propriu-zisa, conform sablonului pe care il avem. Functia __init__ poarta denumirea de constructorul clasei.

Pentru a te referi la elementele unei clase din interiorul acesteia, trebuie sa utilizezi operatorul self. De asemenea, self reprezinta primul parametru pentru orice functie definita in cadrul unei clase. Orice functie sau variabila creata pe primul nivel de indentare apartine automat clasei. Pentru a accesa aceste functii si variabile in alta locatie din cadrul clasei, denumirea lor trebuie sa fie precedata de self si de un punct (ex. self.nume_variabila).

Utilizarea unei clase

Este interesant ca putem crea o clasa, dar cum o putem utiliza? Iata cum poti crea un obiect de tipul FormaGeometrica:

dreptunghi = FormaGeometrica (100,45)

Valorile furnizate intre paranteze sunt de fapt parametri transmisi functiei __init__. Aceasta va fi executata automat, initializand proprietatile x si y ale obiectului cu valorile 100 si respectiv 45. Instanta clasei este retinuta in variabila rectangle.

In acest moment, iti poti imagina instanta clasei noastre, rectangle, ca fiind o colectie de variabile si de functii. Pentru a accesa proprietatile si metodele obiectului din afara clasei vei inlocui cuvantul cheie self cu numele variabilei, respectiv rectangle. De exemplu:

 
#afiseaza aria dreptunghiului:
print dreptunghi.aria()
 
#afiseaza perimetrul dreptunghiului:
print dreptunghi.perimetrul()
 
#seteaza descrierea dreptunghiului
dreptunghi. seteazaDescriere("Un dreptunghi a carui latime este de doua ori mai mare decat inaltimea")
 
#scaleaza dreptunghiul cu 50%
dreptunghi.scaleaza(0.5)
 
#afiseaza aria dreptunghiului scalat
print dreptunghi.aria()

Desigur, poti crea oricat de multe instante ale unei clase. Iata un exemplu:

 
dreptunghi_lung = Shape(120,10)
dreptunghi_inalt = Shape(130,120)

Ambele obiecte, dreptunghi_lung cat si dreptunghi_inalt, au propriile functii si variabile - sunt total independente una de alta.

Iata cativa termeni specifici pentru programarea orientata pe obiecte:

• Atunci cand cream o clasa se numeste ca o definim.
• Gruparea variabilelor si metodelor similare poarta numele de incapsulare.
• O variabila definita in interiorul unei clase poarta numele de proprietate.
• O functie definita in interiorul unei clase poarta numele de metoda.
• Un obiect este o instanta a unei clase.
• O clasa reprezinta o structura de date - ea retine informatii si defineste metodele necesare pentru procesarea acestora.

Mostenirea

Cunoastem modul in care clasele grupeaza variabile si functii, cunoscute sub denumirea de atribute si metode, in asa fel incat datele si codul care le proceseaza sa se afle in aceeasi locatie. Putem crea oricate instante ale acelei clase, pentru a nu mai fi necesar sa scriem un nou cod pentru fiecare obiect pe care il cream. Dar in cazul adaugarii de noi elemente designului unei biciclete? Aici intervine mostenirea.

Programarea orientata pe obiecte le permite claselor sa mosteneasca starile si comportamentele comune din alte clase, ceea ce inseamna crearea unei clase copil pe baza unei clase parinte. Clasa copil contine toate proprietatile si metodele clasei parinte, dar poate include si elemente noi. In cazul in care vreuna dintre noile proprietati sau metode are aceeasi denumire ca o proprietate sau metoda din clasa parinte, vor fi utilizate cele din clasa copil.


Python face mostenirea foarte usoara. Iti amintesti de clasa FormaGeometrica? Sa zicem ca am vrea sa definim o clasa noua, sa spunem un patrat, pe baza clasei precedente:

 
class Patrat(FormaGeometrica):
    def __init__(self,x):
    self.x = x
    self.y = x

Dupa cum poti observa, numele clasei parinte a fost trecut intre paranteze dupa numele clasei copil. Aceasta inseamna ca noua clasa Patrat va contine toate proprietatile si metodele clasei FormaGeometrica. Singurul lucru pe care trebuie sa-l mai faci este sa redefinesti functia __init__, astfel incat latimea (x) si inaltimea(y) obiectului de tip Patrat sa fie egale.

Sa aplicam ce am invatat si sa cream o noua clasa, de aceasta data mostenita din Patrat:

 
class PatratDublu(Patrat):
    def __init__(self,y):
        self.x = 2 * y
        self.y = y
    def perimetrul(self):
        return 2 * self.x + 3 * self.y

Aceasta clasa va reprezenta doua patrate lipite, ceea ce inseamna ca trebuie sa redefinim si functia ce calculeaza perimetrul. Ca exercitiu, incearca sa creezi o instanta a acestei clase.

Referinte si liste de obiecte

Operatorul de atribuire functioneaza diferit pentru obiecte. In cazul variabilelor scalare, daca scriem variabila2 = variabila1 inseamna ca variabila2 va prelua valoarea variabilei 1.

In cazul obiectelor, daca avem o atribuire instanta2 = instanta1, cele doua variabile vor reprezenta referinte catre acelasi obiect. Cu alte cuvinte, daca proprietatile obiectului instanta1 sunt modificate, aceasta modificare va fi vizibila si in instanta2.

In alte limbaje, astfel de atribuiri sunt efectuate cu ajutorul pointerilor, dar in python aceasta operatie se efectueaza transparent.

Aspectul final pe care il vom discuta se refera la dictionare de obiecte. Tinand minte ceea ce tocmai am invatat despre pointeri, putem atribui o instanta a unei clase unei intrari dintr-o lista sau dictionar. Aceasta permite gruparea mai multor obiecte sub un singur nume de lista sau dictionar. Iata un exemplu:

 
# Acest exemplu presupune ca au fost deja definite 
# clasele FormaGeometrica, Patrat si PatratDublu.
# Mai intai cream dictionarul: 
dictionary = {}
 
# Apoi definim cateva obiecte pe care le adaugam in dictionar:
dictionary["Patrat dublu 1"] = PatratDublu(5)
dictionary["Dreptunghi lung"] = FormaGeometrica(600,45)
 
# Calculam aria unui obiect din dictionar:
print dictionary["Dreptunghi lung"].aria()
 
# Setam autorul unui obiect din dictionary, apoi il afisam
dictionary["Patrat dublu 1"].seteazaAutor("Autor")
print dictionary["Patrat dublu 1"].autor

Dupa cum poti observa, pur si simplu am inlocuit numele de variabila din partea stanga cu un element din dictionar. Interesant, nu?

Cam atat despre clase si obiecte. In urmatorul tutorial vei putea citi despre module si utilizarea lor in Python.


Copyright © 2008-2010 E-LEARN.ro. Toate drepturile rezervate. Conceput si realizat de Neokinetics Software.