Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Python

Объектно-ориентированное программирование в Python: полное руководство

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

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

Оператор class создает новое определение класса. Имя класса сразу следует за ключевым словом class и двоеточием:

class ClassName:
    'Optional class documentation string'
    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)

Создание экземпляров объектов

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

# Создание первого объекта класса Employee
emp1 = Employee("Zara", 2000)
# Создание второго объекта класса Employee
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)

emp1 = Employee("Zara", 2000)
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  # Добавить атрибут 'age'
emp1.age = 8  # Изменить атрибут 'age'
del emp1.age  # Удалить атрибут 'age'

Вместо обычных операторов для доступа к атрибутам можно использовать функции:

hasattr(emp1, 'age')    # True, если атрибут 'age' существует
getattr(emp1, 'age')    # Значение атрибута 'age'
setattr(emp1, 'age', 8) # Установить 'age' в 8
delattr(emp1, 'age')    # Удалить атрибут 'age'

Встроенные атрибуты класса

Каждый класс Python хранит следующие встроенные атрибуты, доступные через точечный оператор:

Пример доступа

#!/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': , 'empCount': 2, 'displayEmployee': , '__doc__': 'Common base class for all employees', '__init__': }

Уничтожение объектов (сборка мусора)

Python автоматически удаляет ненужные объекты (встроенные типы или экземпляры классов) для освобождения памяти. Процесс периодического восстановления блоков памяти, которые больше не используются, называется сборкой мусора (Garbage Collection).

Сборщик мусора Python запускается во время выполнения программы и срабатывает, когда счетчик ссылок объекта достигает нуля. Счетчик ссылок меняется по мере изменения количества псевдонимов, указывающих на объект.

Счетчик увеличивается при назначении объекту нового имени или размещении в контейнере (список, кортеж, словарь). Уменьшается при удалении через del, переназначении ссылки или выходе ссылки из области видимости. Когда счетчик достигает нуля, Python автоматически собирает объект.

a = 40      # Создать объект <40>
b = a       # Увеличить счетчик ссылок <40>
c = [b]     # Увеличить счетчик ссылок <40>
del a       # Уменьшить счетчик ссылок <40>
b = 100     # Уменьшить счетчик ссылок <40>
c[0] = -1   # Уменьшить счетчик ссылок <40>

Обычно вы не заметите, когда сборщик мусора уничтожает потерянный экземпляр и освобождает его память. Но класс может реализовать специальный метод __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))  # вывод идентификаторов объектов
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:
    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):
    def __init__(self):
        print("Calling child constructor")
    def childMethod(self):
        print('Calling child method')

c = Child()
c.childMethod()
c.parentMethod()
c.setAttr(200)
c.getAttr()

Результат:

Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200

Можно наследовать от нескольких родительских классов:

class A:
    ...
class B:
    ...
class C(A, B):
    ...

Функции issubclass() и isinstance() проверяют отношения классов и экземпляров:

Переопределение методов

Можно всегда переопределять методы родительского класса. Причина — необходимость специальной или иной функциональности в подклассе.

Пример

#!/usr/bin/python
class Parent:
    def myMethod(self):
        print('Calling parent method')

class Child(Parent):
    def myMethod(self):
        print('Calling child method')

c = Child()
c.myMethod()

Результат:

Calling child method

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

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

№Метод, описание и пример вызова
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 
    print(counter.__secretCount)
AttributeError: JustCounter instance has no attribute '__secretCount'

Python защищает такие члены, внутренне меняя имя для включения имени класса. Доступ к таким атрибутам возможен как object._className__attrName. Если заменить последнюю строку на:

print(counter._JustCounter__secretCount)

Результат:

1
2
2

Python

  1. Классы и объекты в C#: Фундаменты надёжного ООП
  2. Освоение типов данных в Python: практическое руководство
  3. Мастерство операторов Python: Полное руководство
  4. Оператор pass в Python: практическое руководство
  5. Словари в Python: создание, манипуляции и продвинутые техники
  6. Пользовательские исключения в Python: практическое руководство
  7. Объектно-ориентированное программирование в Python: классы, наследование, инкапсуляция и полиморфизм
  8. Наследование в Python: концепции, синтаксис и практические примеры
  9. Паттерн Singleton в Java: как реализовать и безопасно использовать
  10. Автоматизированное визуальное отслеживание объектов на Raspberry Pi и OpenCV