Python – Object Oriented

Opinie

Python jest językiem zorientowanym obiektowo odkąd istnieje. Z tego powodu tworzenie i używanie klas i obiektów jest bardzo proste. Ten rozdział pomoże Ci stać się ekspertem w korzystaniu z obsługi programowania obiektowego w Pythonie.

Jeśli nie masz żadnego wcześniejszego doświadczenia z programowaniem obiektowym (OO), możesz chcieć skonsultować się z kursem wprowadzającym do tego języka lub przynajmniej z jakimś samouczkiem, aby poznać podstawowe pojęcia.

Jednakże, tutaj jest małe wprowadzenie do programowania zorientowanego obiektowo (OOP), aby przyśpieszyć –

Przegląd terminologii OOP

  • Klasa – zdefiniowany przez użytkownika prototyp obiektu, który definiuje zestaw atrybutów, które charakteryzują każdy obiekt tej klasy. Atrybutami są członkowie danych (zmienne klasy i zmienne instancji) oraz metody, dostępne za pomocą notacji kropkowej.

  • Zmienna klasy – Zmienna, która jest wspólna dla wszystkich instancji klasy. Zmienne klasowe są definiowane wewnątrz klasy, ale poza jakimikolwiek jej metodami. Zmienne klasowe nie są używane tak często, jak zmienne instancji.

  • Członek danych – Zmienna klasowa lub zmienna instancji, która przechowuje dane związane z klasą i jej obiektami.

  • Przeciążanie funkcji – Przypisanie więcej niż jednego zachowania określonej funkcji. Wykonywana operacja różni się w zależności od typów obiektów lub argumentów biorących udział.

  • Zmienna instancyjna – Zmienna, która jest zdefiniowana wewnątrz metody i należy tylko do bieżącej instancji klasy.

  • Dziedziczenie – Przekazywanie cech danej klasy innym klasom, które są z niej pochodne.

  • Instancja – Indywidualny obiekt pewnej klasy. Na przykład obiekt obj, który należy do klasy Circle, jest instancją klasy Circle.

  • Instancja – Tworzenie instancji klasy.

  • Metoda – Specjalny rodzaj funkcji, która jest zdefiniowana w definicji klasy.

  • Obiekt – Unikalna instancja struktury danych, która jest zdefiniowana przez swoją klasę. Obiekt zawiera zarówno członków danych (zmienne klasy i zmienne instancji), jak i metody.

  • Przeciążanie operatorów – Przypisanie więcej niż jednej funkcji do określonego operatora.

Tworzenie klas

Konstrukcja klasy tworzy nową definicję klasy. Nazwa klasy następuje bezpośrednio po słowie kluczowym class, po którym następuje dwukropek w następujący sposób –

class ClassName: 'Optional class documentation string' class_suite
  • Klasa posiada łańcuch dokumentacji, do którego można uzyskać dostęp poprzez ClassName.__doc__.

  • Konstrukcja class_suite składa się ze wszystkich deklaracji składowych definiujących członków klasy, atrybuty danych i funkcje.

Przykład

Poniżej przedstawiono przykład prostej klasy Pythona –

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
  • Zmienna empCount jest zmienną klasową, której wartość jest wspólna dla wszystkich instancji tej klasy. Dostęp do niej można uzyskać jako Employee.empCount z wnętrza klasy lub spoza klasy.

  • Pierwsza metoda __init__() jest specjalną metodą, która jest nazywana konstruktorem klasy lub metodą inicjalizacyjną, którą Python wywołuje, gdy tworzysz nową instancję tej klasy.

  • Inne metody klasy deklarujesz jak normalne funkcje z tym wyjątkiem, że pierwszym argumentem każdej metody jest self. Python dodaje argument self do listy za Ciebie; nie musisz go dołączać podczas wywoływania metod.

Tworzenie instancji obiektów

Aby utworzyć instancje klasy, wywołujesz klasę za pomocą nazwy klasy i przekazujesz argumenty, które przyjmuje jej metoda __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)

Dostęp do atrybutów

Dostęp do atrybutów obiektu uzyskujesz za pomocą operatora kropki z obiektem. Dostęp do zmiennej klasy byłby uzyskiwany przy użyciu nazwy klasy w następujący sposób –

emp1.displayEmployee()emp2.displayEmployee()print "Total Employee %d" % Employee.empCount

Teraz, łącząc wszystkie koncepcje razem –

#!/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

Gdy powyższy kod jest wykonywany, daje następujący wynik –

Name : Zara ,Salary: 2000Name : Manni ,Salary: 5000Total Employee 2

Możesz dodawać, usuwać, lub modyfikować atrybuty klas i obiektów w dowolnym momencie –

emp1.age = 7 # Add an 'age' attribute.emp1.age = 8 # Modify 'age' attribute.del emp1.age # Delete 'age' attribute.

Zamiast używać normalnych instrukcji dostępu do atrybutów, możesz użyć następujących funkcji –

  • Funkcja getattr(obj, nazwa) – aby uzyskać dostęp do atrybutu obiektu.

  • The hasattr(obj,nazwa) – aby sprawdzić, czy atrybut istnieje, czy nie.

  • The setattr(obj,nazwa,wartość) – aby ustawić atrybut. Jeżeli atrybut nie istnieje, to zostanie utworzony.

  • The delattr(obj,name) – do usunięcia atrybutu.

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'

Wbudowane atrybuty klasy

Każda klasa Pythona posiada następujące wbudowane atrybuty i można się do nich dostać za pomocą operatora kropki, jak do każdego innego atrybutu –

  • __dict__ – Słownik zawierający przestrzeń nazw klasy.

  • __doc__ – Łańcuch dokumentacji klasy lub brak, jeśli jest niezdefiniowana.

  • __name__ – Nazwa klasy.

  • __module__ – Nazwa modułu, w którym zdefiniowana jest klasa. Ten atrybut to „__main__” w trybie interaktywnym.

  • __bases__ – Możliwie pusta tuple zawierająca klasy bazowe, w kolejności ich występowania na liście klas bazowych.

Dla powyższej klasy spróbujmy uzyskać dostęp do wszystkich tych atrybutów –

#!/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__

Gdy powyższy kod zostanie wykonany, daje następujący wynik –

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>}

Usuwanie obiektów (Garbage Collection)

Python usuwa niepotrzebne obiekty (typy wbudowane lub instancje klas) automatycznie, aby zwolnić miejsce w pamięci. Proces, w którym Python okresowo odzyskuje bloki pamięci, które nie są już używane, jest określany jako Garbage Collection.

Python’s garbage collector działa podczas wykonywania programu i jest uruchamiany, gdy liczba referencji obiektu osiągnie zero. Liczba referencji obiektu zmienia się, gdy zmienia się liczba aliasów, które na niego wskazują.

Liczba referencji obiektu wzrasta, gdy przypisuje mu się nową nazwę lub umieszcza w kontenerze (liście, krotce lub słowniku). Liczba referencji obiektu zmniejsza się, gdy jest on usuwany za pomocą del, jego referencja jest ponownie przypisywana lub jego referencja wychodzi poza zakres. Gdy liczba referencji obiektu osiągnie zero, Python automatycznie go zbiera.

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> 

Zazwyczaj nie zauważysz, kiedy garbage collector zniszczy osieroconą instancję i odzyska jej miejsce. Ale klasa może zaimplementować specjalną metodę __del__(), zwaną destruktorem, która jest wywoływana, gdy instancja ma zostać zniszczona. Ta metoda może być użyta do wyczyszczenia wszelkich zasobów niepamięci używanych przez instancję.

Przykład

Ten destruktor __del__() wypisuje nazwę klasy instancji, która ma zostać zniszczona –

#!/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

Gdy powyższy kod jest wykonywany, daje następujący wynik –

3083401324 3083401324 3083401324Point destroyed

Uwaga – Idealnie, powinieneś zdefiniować swoje klasy w osobnym pliku, a następnie zaimportować je do głównego pliku programu używając instrukcji import.

Dziedziczenie klas

Zamiast zaczynać od zera, możesz stworzyć klasę poprzez wyprowadzenie jej z wcześniej istniejącej klasy poprzez wymienienie klasy nadrzędnej w nawiasie po nazwie nowej klasy.

Klasa dziecięca dziedziczy atrybuty swojej klasy nadrzędnej, i możesz używać tych atrybutów tak jakby były zdefiniowane w klasie dziecięcej. Klasa dziecięca może również nadpisać członków danych i metody z rodzica.

Syntaktyka

Klasy pochodne są deklarowane podobnie jak ich klasa macierzysta; jednak lista klas bazowych, z których mają dziedziczyć jest podana po nazwie klasy –

class SubClassName (ParentClass1): 'Optional class documentation string' class_suite

Przykład

#!/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

Gdy powyższy kod jest wykonywany, daje następujący wynik –

Calling child constructorCalling child methodCalling parent methodParent attribute : 200

Podobnie, możesz prowadzić klasę z wielu klas nadrzędnych w następujący sposób –

class A: # define your class A.....class B: # define your class B.....class C(A, B): # subclass of A and B.....

Możesz użyć funkcji issubclass() lub isinstance() do sprawdzenia relacji dwóch klas i instancji.

  • Funkcja boolean issubclass(sub, sup) zwraca wartość true, jeśli podana podklasa sub jest rzeczywiście podklasą nadklasy sup.

  • Funkcja boolean isinstance(obj, Class) zwraca wartość true, jeśli obj jest instancją klasy Class lub jest instancją podklasy Class

Nadpisywanie metod

Zawsze możesz nadpisać metody klasy nadrzędnej. Jednym z powodów nadpisywania metod rodzica jest to, że możesz chcieć specjalnej lub innej funkcjonalności w swojej podklasie.

Przykład

#!/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

Gdy powyższy kod jest wykonywany, daje następujący wynik –

Calling child method

Base Overloading Methods

Poniższa tabela wymienia niektóre ogólne funkcjonalności, które możesz nadpisać w swoich własnych klasach –

Sr.No. Metoda, Opis & Przykładowe wywołanie
1

__init__ ( self )

Konstruktor (z dowolnymi opcjonalnymi argumentami)

Przykładowe wywołanie : obj = className(args)

2

__del__( self )

Destruktor, usuwa obiekt

Przykładowe wywołanie : del obj

3

__repr__( self )

Odwzorowanie łańcucha wartości

Przykładowe wywołanie : repr(obj)

4

__str__( self )

Wydrukowalna reprezentacja ciągu znaków

Przykładowe wywołanie : str(obj)

5

__cmp__ ( self, x )

Porównanie obiektów

Przykładowe wywołanie : cmp(obj, x)

Przeciążanie operatorów

Załóżmy, że stworzyłeś klasę Vector do reprezentowania dwuwymiarowych wektorów, co się stanie, gdy użyjesz operatora plusa, aby je dodać? Najprawdopodobniej Python krzyknie na Ciebie.

Mógłbyś jednak zdefiniować metodę __add__ w swojej klasie, aby wykonać dodawanie wektorów, a wtedy operator plus zachowywałby się zgodnie z oczekiwaniami –

Przykład

#!/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

Gdy powyższy kod jest wykonywany, daje następujący wynik –

Vector(7,8)

Ukrywanie danych

Atrybuty obiektu mogą, ale nie muszą być widoczne poza definicją klasy. Musisz nazwać atrybuty z przedrostkiem podwójnego podkreślenia, a te atrybuty nie będą bezpośrednio widoczne dla osób z zewnątrz.

Przykład

#!/usr/bin/pythonclass JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print self.__secretCountcounter = JustCounter()counter.count()counter.count()print counter.__secretCount

Gdy powyższy kod jest wykonywany, daje następujący wynik –

12Traceback (most recent call last): File "test.py", line 12, in <module> print counter.__secretCountAttributeError: JustCounter instance has no attribute '__secretCount'

Python chroni tych członków przez wewnętrzną zmianę nazwy, aby zawierała nazwę klasy. Możesz uzyskać dostęp do takich atrybutów jako object._className__attrName. Jeśli zastąpiłbyś swoją ostatnią linię następującą, wtedy to działa dla ciebie –

.........................print counter._JustCounter__secretCount

Gdy powyższy kod jest wykonywany, daje następujący wynik –

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.