Python является объектно-ориентированным языком с того времени, как он начал существовать. В связи с этим, создание и использование классов и объектов прямо-таки легко. Эта глава поможет вам стать экспертом в использовании объектно-ориентированного программирования в Python.
Если у вас нет какого-либо предыдущего опыта работы с объектно-ориентированным (ОО) программированием, вы можете пройти вводный курс по нему или, по крайней мере, прочитать учебник, чтобы у вас было понимание основных концепций.
Однако, здесь есть небольшое введение в объектно-ориентированное программирование (ООП), чтобы помочь вам:
Оператор class создает новое определение класса. Имя класса следует сразу за ключевым словом class с последующим двоеточием, следующим образом:
class ClassName: 'Optional class documentation string' class_suite
Ниже приведен пример простого класса в Python:
class Employee: 'Общий базовый класс для всех сотрудников' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Всего сотрудников %d" % Employee.empCount def displayEmployee(self): print "Имя : ", self.name, ", Зарплата: ", self.salary
Для создания экземпляров класса, вызывается класс, используя имя класса и передать в аргументах метод __init__.
Это создаст первый объект класса сотрудника emp1 = Employee("AndreyEx", 80000) Это позволит создать второй объект класса employee emp2 = Employee("Alex", 65000)
Вы можете получить доступ к атрибутам объекта, используя оператор точка с объектом. Переменная класса получит доступ, используя имя класса следующим образом:
emp1.displayEmployee() emp2.displayEmployee() print ("Всего сотрудников %d" % Employee.empCount)
Теперь, сложив все понятия вместе:
#!/usr/bin/python3 class Employee: 'Общий базовый класс для всех сотрудников' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print ("Всего сотрудников %d" % Employee.empCount) def displayEmployee(self): print ("Имя : ", self.name, ", Зарплата: ", self.salary) #Это создаст первый объект класса сотрудника" emp1 = Employee("AndreyEx", 80000) #Это позволит создать второй объект класса employee" emp2 = Employee("Alex", 65000) emp1.displayEmployee() emp2.displayEmployee() print ("Всего сотрудников %d" % Employee.empCount)
Когда этот код выполниться, он выведет следующий результат:
Имя : AndreyEx,Зарплата: 80000 Имя : Alex,Зарплата: 65000 Всего сотрудников 2
Вы можете добавлять, удалять или изменять атрибуты классов и объектов в любое время:
emp1.salary = 7000 # Add an 'salary' attribute. emp1.name = 'xyz' # Modify 'age' attribute. del emp1.salary # Delete 'age' attribute.
Вместо того, чтобы использовать обычные заявления атрибутов доступа, вы можете использовать следующие функции:
hasattr(emp1, 'salary') # Возвращает true, если атрибут 'salary' существует getattr(emp1, 'salary') # Возвращает значение атрибута 'salary' setattr(emp1, 'salary', 7000) # Устанавливает атрибут 'salary' в 70000 delattr(emp1, 'salary') # Удаляет атрибут 'salary'
Каждый класс Python поддерживает следующие встроенные атрибуты и их можно получить с помощью оператора точки, как и любой другой атрибут:
Для приведенного выше класса давайте попробуем открыть все эти атрибуты:
#!/usr/bin/python3 class Employee: 'Общий базовый класс для всех сотрудников' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print ("Всего сотрудников %d" % Employee.empCount) def displayEmployee(self): print ("Имя : ", self.name, ", Зарплата: ", self.salary) emp1 = Employee("AndreyEx", 80000) emp2 = Employee("Alex", 65000) print ("Employee.__doc__:", Employee.__doc__) print ("Employee.__name__:", Employee.__name__) print ("Employee.__module__:", Employee.__module__) print ("Employee.__bases__:", Employee.__bases__) print ("Employee.__dict__:", Employee.__dict__ )
Когда этот код выполниться, он выведет следующий результат:
Employee.__doc__: Общий базовый класс для всех сотрудников Employee.__name__: Employee Employee.__module__: __main__ Employee.__bases__: (<class 'object'>,) Employee.__dict__: { 'displayCount': <function Employee.displayCount at 0x0160D2B8>, '__module__': '__main__', '__doc__': 'Общий базовый класс для всех сотрудников', 'empCount': 2, '__init__': <function Employee.__init__ at 0x0124F810>, 'displayEmployee': <function Employee.displayEmployee at 0x0160D300>, '__weakref__': <attribute '__weakref__' of 'Employee' objects>, '__dict__': <attribute '__dict__' of 'Employee' objects> }
Python удаляет ненужные объекты (встроенные типы или экземпляры классов) автоматически, чтобы освободить место в памяти. Процесс, посредством которого Python периодически восстанавливает блоки памяти, которые больше не находятся в использовании называется как сборщики мусора.
Сборщик мусора в Python работают во время выполнения программы и срабатывают, когда счетчик ссылок объекта достигает нуля. Счетчик ссылок объекта изменяется, как число псевдонимов, которые указывают на ее изменения.
Счетчик ссылок объекта увеличивается, когда ему присваивается новое имя или помещается в контейнер (список, кортеж, или словарь). Счетчик ссылок объекта уменьшается, когда он удаляется с del, его ссылка переназначается, или его ссылка выходит из области видимости. Когда счетчик ссылок объекта достигает нуля, Python собирает его автоматически.
a = 40 # Создание объекта <40> b = a # Увеличение счетчика ссылок <40> c = [b] # Увеличение счетчика ссылок <40> del a # Уменьшение счетчика ссылок <40> b = 100 # Уменьшение счетчика ссылок <40> c[0] = -1 # Уменьшение счетчика ссылок <40>
Как правило, вы не замечаете, когда сборщик мусора уничтожает обнулившийся экземпляр и высвобождает его пространство. Тем не менее, класс может реализовать специальный метод __del __(), называется деструктор, который вызывается, когда экземпляр собирается быть уничтоженным. Этот метод может быть использован для очистки любых ресурсов из памяти, используемых экземпляр.
Деструктор __del __ () печатает имя класса экземпляра, который собирается быть уничтожен:
#!/usr/bin/python3 class 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 = pt1 pt3 = pt1 print (id(pt1), id(pt2), id(pt3)); # печатает идентификаторы obejcts del pt1 del pt2 del pt3
Когда этот код выполниться, он выведет следующий результат:
3083401324 3083401324 3083401324 Point destroyed
В приведенном выше примере, предполагая определение класса точки, содержащейся в point.py и нет никакого другого исполняемого кода в нем.
#!/usr/bin/python3 import point p1 = point.Point()
Вместо того чтобы начать с нуля, вы можете создать класс, выводя его из предварительно существующего класса, перечислив родительский класс в скобках после нового имени класса.
Дочерний класс наследует атрибуты своего родительского класса, и вы можете использовать эти атрибуты, как если бы они были определены в дочернем классе. Дочерний класс может также переопределить элементы данных и методы от родителей.
Производные классы объявляются так же, как их родительский класс; Однако, список базовых классов наследуются после имени класса:
class SubClassName (ParentClass1[, ParentClass2, ...]): 'Необязательная строка документации класса' class_suite
#!/usr/bin/python3 class Parent: # определить родительский класс parentAttr = 100 def __init__(self): print ("Вызов родительского конструктора") def parentMethod(self): print ('Вызов родительского метода') def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print ("Родительский атрибут :", Parent.parentAttr) class Child(Parent): # определить дочерний класс def __init__(self): print ("Вызов дочернего конструктора") def childMethod(self): print ('Вызов дочернего метода') c = Child() # дочерний экземпляр c.childMethod() # дочерний экземпляр называет свой метод c.parentMethod() # вызывает родительский метод c.setAttr(200) # снова вызов родительского метода c.getAttr() # снова вызов родительского метода
Когда этот код выполнится, он выведет следующий результат:
Вызов дочернего конструктора Вызов дочернего метода Вызов родительского метода Родительский атрибут : 200
Аналогичным образом, вы можете управлять классом от нескольких родительских классов следующим образом:
class A: # определите свой класс A ..... class B: # определите свой класс B ..... class C(A, B): # Субкласс A и B .....
Вы можете использовать функции issubclass() или isinstance() для проверки отношения двух классов и экземпляров.
Вы всегда можете переопределить методы родительского класса. Одной из причин переопределения методов родителя является то, что вы можете использовать специальную или иную функцию в подклассе.
#!/usr/bin/python3 class Parent: # определить родительский класс def myMethod(self): print ('Вызов родительского метода') class Child(Parent): # определить дочерний класс def myMethod(self): print ('Вызов дочернего метода') c = Child() # дочерний экземпляр c.myMethod() # дочерний класс вызывает переопределенный метод
Когда этот код выполнится, он выведет следующий результат:
Вызов дочернего метода
В следующей таблице перечислены некоторые общие функциональные возможности, которые вы можете переопределить в своих классах:
№ | Метод, описание и пример вызова |
---|---|
1 | __init__ ( self [,args…] ) Конструктор (с любыми дополнительными аргументами) Пример вызова: obj = className(args) |
2 | __del__( self ) Деструктор, удаляет объект Пример вызова: del obj |
3 | __repr__( self ) Evaluatable строковое представление Пример вызова: repr(obj) |
4 | __str__( self ) Версия для печати строкового представления Пример вызова: str(obj) |
5 | __cmp__ ( self, x ) Сравнение объектов Пример вызова: cmp(obj, x) |
Предположим, что вы создали класс Vector для представления двухмерных векторов. Что происходит, когда вы используете оператор плюс, чтобы добавить их? Скорее всего, Python будет ругаться на вас.
Можно, однако, определить метод __add__ в классе для выполнения векторного сложения, а затем оператор плюс будет вести себя в соответствии с ожиданиями:
#!/usr/bin/python3 class 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)
Когда этот код выполнится, он выведет следующий результат:
Vector(7,8)
Атрибуты объекта могут быть или не могут быть видимыми вне определения класса. Вы должны вызвать атрибуты с префиксом двойного подчеркивания, и эти атрибуты тогда не будут непосредственно видны посторонним.
#!/usr/bin/python3 class JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print (self.__secretCount) counter = JustCounter() counter.count() counter.count() print (counter.__secretCount)
Когда этот код выполнится, он выведет следующий результат:
1 2 Traceback (most recent call last): File "test.py", line 12, in <module> print counter.__secretCount AttributeError: JustCounter instance has no attribute '__secretCount'
Python защищает эти члены путем внутреннего изменения имени, чтобы включить имя класса. Вы можете получить доступ к таким атрибутам, как объект ._className__attrName. Если вы заменили бы последнюю строку следующим образом, то она заработает
......................... print (counter._JustCounter__secretCount)
Когда этот код выполниться, вывод будет следующий:
1 2 2