Python — объектно-ориентированный
Предыдущая страницаСледующая страница
Python был объектно-ориентированным языком с момента его появления. Из-за этого создание и использование классов и объектов совершенно несложно. Эта глава поможет вам стать экспертом в использовании поддержки объектно-ориентированного программирования Python.
Если у вас нет предыдущего опыта объектно-ориентированного (ОО) программирования, вы можете ознакомиться с вводным курсом по нему или, по крайней мере, с каким-либо учебным пособием, чтобы иметь представление об основных понятиях.
Тем не менее, вот небольшое введение в объектно-ориентированное программирование (ООП), которое поможет вам ускориться —
Обзор терминологии ООП
-
Класс − Определяемый пользователем прототип объекта, определяющий набор атрибутов, характеризующих любой объект класса. Атрибуты — это члены данных (переменные класса и переменные экземпляра) и методы, доступ к которым осуществляется через запись через точку.
-
Переменная класса − Переменная, которая является общей для всех экземпляров класса. Переменные класса определяются внутри класса, но вне любого из методов класса. Переменные класса используются не так часто, как переменные экземпляра.
-
Член данных − Переменная класса или переменная экземпляра, содержащая данные, связанные с классом и его объектами.
-
Перегрузка функций − Назначение более чем одного поведения конкретной функции. Выполняемая операция зависит от типов задействованных объектов или аргументов.
-
Переменная экземпляра − Переменная, определенная внутри метода и принадлежащая только текущему экземпляру класса.
-
Наследование − Передача характеристик класса другим классам, производным от него.
-
Экземпляр − Отдельный объект определенного класса. Например, объект obj, принадлежащий классу Circle, является экземпляром класса Circle.
-
Экземпляр − Создание экземпляра класса.
-
Метод − Особый вид функции, определенный в определении класса.
-
Объект − Уникальный экземпляр структуры данных, определяемый своим классом. Объект включает в себя как элементы данных (переменные класса и переменные экземпляра), так и методы.
-
Перегрузка оператора − Назначение более чем одной функции конкретному оператору.
Создание классов
класс Оператор создает новое определение класса. Имя класса следует сразу за ключевым словом class. за которым следует двоеточие следующим образом –
class ClassName: 'Optional class documentation string' class_suite
-
У класса есть строка документации, доступ к которой можно получить через ClassName.__doc__ .
-
class_suite состоит из всех операторов компонентов, определяющих члены класса, атрибуты данных и функции.
Пример
Ниже приведен пример простого класса Python —
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
-
Переменная empCount это переменная класса, значение которой является общим для всех экземпляров этого класса. Доступ к этому можно получить как Employee.empCount. внутри класса или вне класса.
-
Первый метод __init__() — это специальный метод, называемый конструктором класса или методом инициализации, который Python вызывает при создании нового экземпляра этого класса.
-
Вы объявляете другие методы класса, как обычные функции, за исключением того, что первым аргументом каждого метода является self. . Python добавляет self аргумент в список для вас; вам не нужно включать его при вызове методов.
Создание экземпляров объектов
Чтобы создать экземпляры класса, вы вызываете класс, используя имя класса, и передаете любые аргументы его __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)
Доступ к атрибутам
Вы получаете доступ к атрибутам объекта, используя оператор точки с объектом. Доступ к переменной класса будет осуществляться с использованием имени класса следующим образом —
emp1.displayEmployee() emp2.displayEmployee() print "Total Employee %d" % Employee.empCount
Теперь объединим все концепции —
Живая демонстрация#!/usr/bin/python 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 "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
Когда приведенный выше код выполняется, он дает следующий результат —
Name : Zara ,Salary: 2000 Name : Manni ,Salary: 5000 Total Employee 2
Вы можете добавлять, удалять или изменять атрибуты классов и объектов в любое время —
emp1.age = 7 # Add an 'age' attribute. emp1.age = 8 # Modify 'age' attribute. del emp1.age # Delete 'age' attribute.
Вместо использования обычных операторов для доступа к атрибутам вы можете использовать следующие функции —
-
getattr(obj, name[, default]) − для доступа к атрибуту объекта.
-
hasattr(obj,name) − чтобы проверить, существует ли атрибут или нет.
-
setattr(obj,name,value) − установить атрибут. Если атрибут не существует, он будет создан.
-
delattr(объект, имя) − для удаления атрибута.
hasattr(emp1, 'age') # Returns true if 'age' attribute exists getattr(emp1, 'age') # Returns value of 'age' attribute setattr(emp1, 'age', 8) # Set attribute 'age' at 8 delattr(empl, 'age') # Delete attribute 'age'
Встроенные атрибуты класса
Каждый класс Python поддерживает встроенные атрибуты, и к ним можно получить доступ с помощью оператора точки, как и к любому другому атрибуту —
-
__dict__ − Словарь, содержащий пространство имен класса.
-
__doc__ − Строка документации класса или нет, если не определено.
-
__имя__ − Имя класса.
-
__модуль__ − Имя модуля, в котором определен класс. Этот атрибут "__main__" в интерактивном режиме.
-
__базы__ − Возможно пустой кортеж, содержащий базовые классы в порядке их появления в списке базовых классов.
Для вышеуказанного класса давайте попробуем получить доступ ко всем этим атрибутам —
Живая демонстрация#!/usr/bin/python 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 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__: Common base class for all employees Employee.__name__: Employee Employee.__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>}
Уничтожение объектов (сборка мусора)
Python автоматически удаляет ненужные объекты (встроенные типы или экземпляры классов), чтобы освободить место в памяти. Процесс, с помощью которого Python периодически освобождает блоки памяти, которые больше не используются, называется сборкой мусора.
Сборщик мусора Python запускается во время выполнения программы и срабатывает, когда счетчик ссылок на объект достигает нуля. Счетчик ссылок на объект изменяется по мере изменения количества псевдонимов, указывающих на него.
Счетчик ссылок на объект увеличивается, когда ему присваивается новое имя или он помещается в контейнер (список, кортеж или словарь). Счетчик ссылок на объект уменьшается, когда он удаляется с помощью del , его ссылка переназначается или ее ссылка выходит за рамки. Когда счетчик ссылок на объект достигает нуля, Python собирает его автоматически.
a = 40 # Create object <40> b = a # Increase ref. count of <40> c = [b] # Increase ref. count of <40> del a # Decrease ref. count of <40> b = 100 # Decrease ref. count of <40> c[0] = -1 # Decrease ref. count of <40>
Обычно вы не заметите, когда сборщик мусора уничтожит потерянный экземпляр и освободит его место. Но класс может реализовать специальный метод __del__() , называемый деструктором, который вызывается перед уничтожением экземпляра. Этот метод можно использовать для очистки любых ресурсов, не связанных с памятью, используемых экземпляром.
Пример
Этот деструктор __del__() выводит имя класса экземпляра, который должен быть уничтожен —
Живая демонстрация#!/usr/bin/python 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) # prints the ids of the obejcts del pt1 del pt2 del pt3
Когда приведенный выше код выполняется, он дает следующий результат —
3083401324 3083401324 3083401324 Point destroyed
Примечание − В идеале вы должны определить свои классы в отдельном файле, а затем импортировать их в основной файл программы с помощью import. заявление.
Наследование классов
Вместо того, чтобы начинать с нуля, вы можете создать класс, производный от уже существующего класса, перечислив родительский класс в круглых скобках после имени нового класса.
Дочерний класс наследует атрибуты своего родительского класса, и вы можете использовать эти атрибуты, как если бы они были определены в дочернем классе. Дочерний класс также может переопределять элементы данных и методы родительского класса.
Синтаксис
Производные классы объявляются так же, как их родительский класс; однако список базовых классов для наследования указывается после имени класса -
class SubClassName (ParentClass1[, ParentClass2, ...]): 'Optional class documentation string' class_suite
Пример
Живая демонстрация#!/usr/bin/python class 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.parentAttr class Child(Parent): # define child class def __init__(self): print "Calling child constructor" def childMethod(self): print 'Calling child method' c = Child() # instance of child c.childMethod() # child calls its method c.parentMethod() # calls parent's method c.setAttr(200) # again call parent's method c.getAttr() # again call parent's method
Когда приведенный выше код выполняется, он дает следующий результат —
Calling child constructor Calling child method Calling parent method Parent attribute : 200
Аналогичным образом вы можете управлять классом из нескольких родительских классов следующим образом:
class A: # define your class A ..... class B: # define your class B ..... class C(A, B): # subclass of A and B .....
Вы можете использовать функции issubclass() или isinstance() для проверки отношений между двумя классами и экземплярами.
-
issubclass(sub, sup) логическая функция возвращает значение true, если заданный подкласс sub действительно является подклассом суперкласса sup .
-
isinstance(obj, Class) логическая функция возвращает true, если obj является экземпляром класса Class или является экземпляром подкласса класса
Переопределение методов
Вы всегда можете переопределить методы родительского класса. Одной из причин переопределения родительских методов является то, что вам могут понадобиться специальные или другие функции в вашем подклассе.
Пример
Живая демонстрация#!/usr/bin/python class 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 child c.myMethod() # child calls overridden method
Когда приведенный выше код выполняется, он дает следующий результат —
Calling child method
Базовые методы перегрузки
В следующей таблице перечислены некоторые общие функции, которые вы можете переопределить в своих собственных классах —
Серийный номер | Метод, описание и пример вызова |
---|---|
1 | <тд>|
2 | <тд>|
3 | <тд>|
4 | <тд>|
5 | <тд>
Перегрузка операторов
Предположим, вы создали класс Vector для представления двумерных векторов. Что происходит, когда вы используете оператор плюс для их добавления? Скорее всего, Python будет на вас орать.
Однако вы можете определить __add__ метод в вашем классе для выполнения сложения векторов, а затем оператор плюса будет вести себя так, как ожидалось -
Пример
Живая демонстрация#!/usr/bin/python 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/python 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 защищает эти члены, внутренне изменяя имя, чтобы включить имя класса. Вы можете получить доступ к таким атрибутам, как object._className__attrName . Если вы замените свою последнюю строку следующим образом, то это сработает для вас —
......................... print counter._JustCounter__secretCount
Когда приведенный выше код выполняется, он дает следующий результат —
1 2 2
Python