Python - объектно-ориентированный

Python с момента своего существования был объектно-ориентированным языком. Благодаря этому создавать и использовать классы и объекты совершенно несложно. Эта глава поможет вам стать экспертом в использовании поддержки объектно-ориентированного программирования Python.

Если у вас нет предыдущего опыта в объектно-ориентированном (ОО) программировании, вы можете проконсультироваться с вводным курсом по нему или, по крайней мере, с каким-либо учебным пособием, чтобы понять основные концепции.

Тем не менее, вот небольшое введение в объектно-ориентированное программирование (ООП), которое поможет вам быстрее -

Обзор терминологии ООП

  • Class- Определяемый пользователем прототип объекта, который определяет набор атрибутов, характеризующих любой объект класса. Атрибуты - это члены данных (переменные класса и переменные экземпляра) и методы, доступ к которым осуществляется через точечную нотацию.

  • Class variable- Переменная, общая для всех экземпляров класса. Переменные класса определены внутри класса, но вне его методов. Переменные класса используются не так часто, как переменные экземпляра.

  • Data member - Переменная класса или переменная экземпляра, которая содержит данные, связанные с классом и его объектами.

  • Function overloading- Назначение более чем одного поведения определенной функции. Выполняемая операция зависит от типов задействованных объектов или аргументов.

  • Instance variable - Переменная, которая определяется внутри метода и принадлежит только текущему экземпляру класса.

  • Inheritance - Передача характеристик класса другим классам, производным от него.

  • Instance- Индивидуальный объект определенного класса. Например, объект obj, принадлежащий классу Circle, является экземпляром класса Circle.

  • Instantiation - Создание экземпляра класса.

  • Method - Особый вид функции, которая определяется в определении класса.

  • Object- Уникальный экземпляр структуры данных, определяемой ее классом. Объект включает как элементы данных (переменные класса и переменные экземпляра), так и методы.

  • Operator overloading - Назначение более одной функции одному оператору.

Создание классов

Оператор класса создает новое определение класса. Имя класса следует сразу за ключевым словом 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(obj, name) - удалить атрибут.

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__ - Строка документации класса или ее нет, если не определено.

  • __name__ - Название класса.

  • __module__- Имя модуля, в котором определен класс. Этот атрибут - «__main__» в интерактивном режиме.

  • __bases__ - Возможно, пустой кортеж, содержащий базовые классы, в порядке их появления в списке базовых классов.

Для вышеуказанного класса давайте попробуем получить доступ ко всем этим атрибутам -

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

Note- В идеале вы должны определить свои классы в отдельном файле, а затем вы должны импортировать их в свой основной файл программы с помощью оператора импорта .

Наследование класса

Вместо того, чтобы начинать с нуля, вы можете создать класс, унаследовав его от уже существующего класса, указав родительский класс в круглых скобках после имени нового класса.

Дочерний класс наследует атрибуты своего родительского класса, и вы можете использовать эти атрибуты, как если бы они были определены в дочернем классе. Дочерний класс также может переопределять элементы данных и методы родительского класса.

Синтаксис

Производные классы объявляются так же, как их родительский класс; однако список базовых классов для наследования дается после имени класса -

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) логическая функция возвращает истину, если данный подкласс sub действительно является подклассом суперкласса sup.

  • В isinstance(obj, Class)логическая функция возвращает истину, если 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

Базовые методы перегрузки

В следующей таблице перечислены некоторые общие функции, которые вы можете переопределить в своих собственных классах.

Sr.No. Метод, описание и пример вызова
1

__init__ ( self [,args...] )

Конструктор (с любыми необязательными аргументами)

Пример вызова: obj = className (args)

2

__del__( self )

Деструктор, удаляет объект

Пример вызова: del obj

3

__repr__( self )

Оцениваемое строковое представление

Пример вызова: repr (obj)

4

__str__( self )

Строковое представление для печати

Пример вызова: str (obj)

5

__cmp__ ( self, x )

Сравнение объектов

Пример вызова: cmp (obj, x)

Операторы перегрузки

Предположим, вы создали класс 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