Python a fost un limbaj orientat pe obiecte încă de când a existat. Din acest motiv, crearea și utilizarea claselor și a obiectelor sunt de-a dreptul ușoare. Acest capitol vă ajută să deveniți un expert în utilizarea suportului de programare orientată pe obiecte al limbajului Python.
Dacă nu aveți nici o experiență anterioară cu programarea orientată pe obiecte (OO), poate doriți să consultați un curs introductiv în acest sens sau cel puțin un tutorial de vreun fel, astfel încât să aveți o înțelegere a conceptelor de bază.
Cu toate acestea, iată o mică introducere în programarea orientată pe obiecte (POO) pentru a vă aduce la viteză –
Vizualizare generală a terminologiei POO
-
Clasă – Un prototip definit de utilizator pentru un obiect care definește un set de atribute care caracterizează orice obiect din clasa respectivă. Atributele sunt membri de date (variabile de clasă și variabile de instanță) și metode, accesate prin notația punct.
-
Variabilă de clasă – O variabilă care este partajată de toate instanțele unei clase. Variabilele de clasă sunt definite în cadrul unei clase, dar în afara oricărei metode a clasei. Variabilele de clasă nu sunt utilizate la fel de frecvent ca variabilele de instanță.
-
Membru de date – O variabilă de clasă sau o variabilă de instanță care conține date asociate cu o clasă și cu obiectele sale.
-
Supraîncărcare de funcții – Atribuirea mai multor comportamente unei anumite funcții. Operația efectuată variază în funcție de tipurile de obiecte sau de argumente implicate.
-
Variabilă de instanță – O variabilă care este definită în interiorul unei metode și care aparține numai instanței curente a unei clase.
-
Ereditate – Transferul caracteristicilor unei clase către alte clase care derivă din ea.
-
Instanță – Un obiect individual al unei anumite clase. Un obiect obj care aparține clasei Circle, de exemplu, este o instanță a clasei Circle.
-
Instantiation – Crearea unei instanțe a unei clase.
-
Method – Un tip special de funcție care este definită în definiția unei clase.
-
Object – O instanță unică a unei structuri de date care este definită de clasa sa. Un obiect cuprinde atât membri de date (variabile de clasă și variabile de instanță), cât și metode.
-
Supraîncărcare de operatori – Atribuirea mai multor funcții unui anumit operator.
Crearea claselor
Expresia class creează o nouă definiție de clasă. Numele clasei urmează imediat după cuvântul cheie class, urmat de două puncte, după cum urmează –
class ClassName: 'Optional class documentation string' class_suite
-
Clasa are un șir de documentație, care poate fi accesat prin ClassName.__doc__.
-
Clasa_suite constă din toate instrucțiunile componente care definesc membrii clasei, atributele de date și funcțiile.
Exemplu
În cele ce urmează este exemplul unei clase Python simple –
class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary
-
Variabila empCount este o variabilă de clasă a cărei valoare este partajată între toate instanțele unei clase din această clasă. Aceasta poate fi accesată ca Employee.empCount din interiorul clasei sau din afara clasei.
-
Prima metodă __init__() este o metodă specială, care se numește constructorul clasei sau metoda de inițializare pe care Python o apelează atunci când creați o nouă instanță a acestei clase.
-
Declarați celelalte metode ale clasei ca și funcțiile normale, cu excepția faptului că primul argument al fiecărei metode este self. Python adaugă argumentul self în listă pentru dumneavoastră; nu trebuie să îl includeți atunci când apelați metodele.
Crearea de obiecte instanță
Pentru a crea instanțe ale unei clase, apelați clasa folosind numele clasei și treceți orice argumente pe care le acceptă metoda sa __init__.
"This would create first object of Employee class"emp1 = Employee("Zara", 2000)"This would create second object of Employee class"emp2 = Employee("Manni", 5000)
Accesarea atributelor
Accesați atributele obiectului folosind operatorul punct cu obiect. Variabila de clasă ar fi accesată folosind numele clasei după cum urmează –
emp1.displayEmployee()emp2.displayEmployee()print "Total Employee %d" % Employee.empCount
Acum, punând toate conceptele laolaltă –
#!/usr/bin/pythonclass Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary"This would create first object of Employee class"emp1 = Employee("Zara", 2000)"This would create second object of Employee class"emp2 = Employee("Manni", 5000)emp1.displayEmployee()emp2.displayEmployee()print "Total Employee %d" % Employee.empCount
Când codul de mai sus este executat, acesta produce următorul rezultat –
Name : Zara ,Salary: 2000Name : Manni ,Salary: 5000Total Employee 2
Puteți adăuga, elimina, sau modificați atributele claselor și obiectelor în orice moment –
În loc să folosiți instrucțiunile normale pentru a accesa atributele, puteți folosi următoarele funcții –
-
Funcția getattr(obj, name) – pentru a accesa atributul obiectului.
-
The hasattr(obj,name) – pentru a verifica dacă un atribut există sau nu.
-
The setattr(obj,name,value) – pentru a seta un atribut. Dacă atributul nu există, atunci acesta va fi creat.
-
The delattr(obj, name) – pentru a șterge un atribut.
hasattr(emp1, 'age') # Returns true if 'age' attribute existsgetattr(emp1, 'age') # Returns value of 'age' attributesetattr(emp1, 'age', 8) # Set attribute 'age' at 8delattr(empl, 'age') # Delete attribute 'age'
Atributele încorporate ale clasei
Care clasă Python păstrează următoarele atribute încorporate și pot fi accesate folosind operatorul dot ca orice alt atribut –
-
__dict__ – Dicționar care conține spațiul de nume al clasei.
-
__doc__ – Șir de caractere de documentare a clasei sau niciunul, dacă este nedefinită.
-
__name__ – Numele clasei.
-
__module__ – Numele modulului în care este definită clasa. Acest atribut este „__main__” în modul interactiv.
-
__baze__ – Un tuplu posibil gol care conține clasele de bază, în ordinea apariției lor în lista de clase de bază.
Pentru clasa de mai sus să încercăm să accesăm toate aceste atribute –
#!/usr/bin/pythonclass Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salaryprint "Employee.__doc__:", Employee.__doc__print "Employee.__name__:", Employee.__name__print "Employee.__module__:", Employee.__module__print "Employee.__bases__:", Employee.__bases__print "Employee.__dict__:", Employee.__dict__
Când codul de mai sus este executat, acesta produce următorul rezultat –
Employee.__doc__: Common base class for all employeesEmployee.__name__: EmployeeEmployee.__module__: __main__Employee.__bases__: ()Employee.__dict__: {'__module__': '__main__', 'displayCount':<function displayCount at 0xb7c84994>, 'empCount': 2, 'displayEmployee': <function displayEmployee at 0xb7c8441c>, '__doc__': 'Common base class for all employees', '__init__': <function __init__ at 0xb7c846bc>}
Distrugerea obiectelor (Garbage Collection)
Python șterge automat obiectele inutile (tipuri încorporate sau instanțe de clase) pentru a elibera spațiu de memorie. Procesul prin care Python recuperează periodic blocuri de memorie care nu mai sunt utilizate este denumit Garbage Collection.
Colectorul de gunoi al lui Python rulează în timpul execuției programului și este declanșat atunci când numărul de referințe al unui obiect ajunge la zero. Numărul de referințe al unui obiect se modifică pe măsură ce se schimbă numărul de alias-uri care îl indică.
Contorul de referințe al unui obiect crește atunci când i se atribuie un nume nou sau este plasat într-un container (listă, tuple sau dicționar). Numărul de referințe al obiectului scade atunci când acesta este șters cu del, când referința sa este realocată sau când referința sa iese din domeniul de aplicare. Când numărul de referințe al unui obiect ajunge la zero, Python îl colectează automat.
a = 40 # Create object <40>b = a # Increase ref. count of <40> c = # Increase ref. count of <40> del a # Decrease ref. count of <40>b = 100 # Decrease ref. count of <40> c = -1 # Decrease ref. count of <40>
În mod normal, nu veți observa când colectorul de gunoi distruge o instanță orfană și îi revendică spațiul. Dar o clasă poate implementa metoda specială __del__(), numită destructor, care este invocată atunci când instanța este pe cale să fie distrusă. Această metodă poate fi utilizată pentru a curăța orice resurse care nu sunt utilizate în memorie de către o instanță.
Exemplu
Acest destructor __del__() tipărește numele clasei unei instanțe care este pe cale să fie distrusă –
#!/usr/bin/pythonclass Point: def __init__( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print class_name, "destroyed"pt1 = Point()pt2 = pt1pt3 = pt1print id(pt1), id(pt2), id(pt3) # prints the ids of the obejctsdel pt1del pt2del pt3
Când codul de mai sus este executat, produce următorul rezultat –
3083401324 3083401324 3083401324Point destroyed
Nota – În mod ideal, ar trebui să vă definiți clasele într-un fișier separat, apoi să le importați în fișierul principal al programului, folosind instrucțiunea import.
Heredarea claselor
În loc să începeți de la zero, puteți crea o clasă derivând-o dintr-o clasă preexistentă prin enumerarea clasei părinte între paranteze după numele noii clase.
Clasa copil moștenește atributele clasei părinte și puteți utiliza aceste atribute ca și cum ar fi fost definite în clasa copil. O clasă copil poate, de asemenea, să suprascrie membrii de date și metodele din clasa părinte.
Sintaxa
Classele derivate sunt declarate la fel ca și clasa lor părinte; cu toate acestea, o listă de clase de bază din care să moștenească este dată după numele clasei –
class SubClassName (ParentClass1): 'Optional class documentation string' class_suite
Exemplu
#!/usr/bin/pythonclass Parent: # define parent class parentAttr = 100 def __init__(self): print "Calling parent constructor" def parentMethod(self): print 'Calling parent method' def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print "Parent attribute :", Parent.parentAttrclass Child(Parent): # define child class def __init__(self): print "Calling child constructor" def childMethod(self): print 'Calling child method'c = Child() # instance of childc.childMethod() # child calls its methodc.parentMethod() # calls parent's methodc.setAttr(200) # again call parent's methodc.getAttr() # again call parent's method
Când codul de mai sus este executat, acesta produce următorul rezultat –
Calling child constructorCalling child methodCalling parent methodParent attribute : 200
În mod similar, puteți conduce o clasă din mai multe clase părinte după cum urmează –
class A: # define your class A.....class B: # define your class B.....class C(A, B): # subclass of A and B.....
Puteți utiliza funcțiile issubclass() sau isinstance() pentru a verifica o relație între două clase și instanțe.
-
Funcția booleană issubclass(sub, sup) returnează true dacă subclasa dată sub este într-adevăr o subclasă a superclasei sup.
-
Funcția booleană isinstance(obj, Class) returnează true dacă obj este o instanță a clasei Class sau este o instanță a unei subclase a clasei Class
Înlocuirea metodelor
Întotdeauna puteți suprascrie metodele clasei părinte. Un motiv pentru a suprascrie metodele părintelui este acela că este posibil să doriți o funcționalitate specială sau diferită în subclasa dumneavoastră.
Exemplu
#!/usr/bin/pythonclass Parent: # define parent class def myMethod(self): print 'Calling parent method'class Child(Parent): # define child class def myMethod(self): print 'Calling child method'c = Child() # instance of childc.myMethod() # child calls overridden method
Când codul de mai sus este executat, acesta produce următorul rezultat –
Calling child method
Base Overloading Methods
Tabelul următor enumeră câteva funcționalități generice pe care le puteți suprascrie în propriile clase –
Sr.No. | Metodă, Descriere & Exemplu de apel |
---|---|
1 |
__init__ ( self ) Constructor (cu orice argumente opționale) Exemplu de apel : obj = className(args) |
2 |
__del__( self ) Destructor, șterge un obiect Semplu de apel : del obj |
3 |
__repr__( self ) Reprezentare șir de caractere evaluabile Apel de exemplu : repr(obj) |
4 |
__str__( self ) Reprezentare șir de caractere imprimabil Apel de exemplu : str(obj) |
5 |
__cmp__ ( self, x ) Comparare obiecte Apel de probă : cmp(obj, x) |
Să presupunem că ați creat o clasă Vector pentru a reprezenta vectori bidimensionali, ce se întâmplă atunci când folosiți operatorul plus pentru a-i aduna? Cel mai probabil, Python va țipa la dvs.
Ați putea, totuși, să definiți metoda __add__ în clasa dvs. pentru a efectua adunarea vectorilor și atunci operatorul plus se va comporta conform așteptărilor –
Exemplu
#!/usr/bin/pythonclass Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b)v1 = Vector(2,10)v2 = Vector(5,-2)print v1 + v2
Când codul de mai sus este executat, acesta produce următorul rezultat –
Vector(7,8)
Ascunderea datelor
Atributele unui obiect pot sau nu pot fi vizibile în afara definiției clasei. Trebuie să denumiți atributele cu un prefix cu două liniuțe de subliniere, iar aceste atribute nu sunt apoi să fie direct vizibile pentru cei din exterior.
Exemplu
#!/usr/bin/pythonclass JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print self.__secretCountcounter = JustCounter()counter.count()counter.count()print counter.__secretCount
Când codul de mai sus este executat, acesta produce următorul rezultat –
12Traceback (most recent call last): File "test.py", line 12, in <module> print counter.__secretCountAttributeError: JustCounter instance has no attribute '__secretCount'
Python protejează acești membri prin schimbarea internă a numelui pentru a include numele clasei. Puteți accesa astfel de atribute ca object._className__attrName. Dacă ați înlocui ultima linie ca fiind următoarea, atunci funcționează pentru dumneavoastră –
.........................print counter._JustCounter__secretCount
Când codul de mai sus este executat, acesta produce următorul rezultat –