ООП для многих начинающих представляет определенные трудности в понимании этого вопроса. У меня также были самые общие понимания ООП. С учетом того, что при изучении python регулярно сталкиваюсь с понятием класса, я решил углубиться в эту тему и конечно же решил создать конспект из нескольких частей.
Ранее мы писали любой код в процедурном стиле. Нормально писать программу в процедурном стиле, но большинству программ, особенно средних и крупных, объектно-ориентированный стиль дает значимые преимущества, как на этапе разработки, так и на этапе поддержки программы. В основе объектно-ориентированного программирования лежит принцип того, что все состоит из объектов.
ООП
Объектно-ориентированное программирование (ООП) в Python – это методология программирования, в которой программа структурируется вокруг объектов, которые представляют реальные или абстрактные сущности. В ООП фокусировка идет на объектах, которыми нужно манипулировать. Благодаря ООП появилась возможность создавать модульные, масштабируемые и легко поддерживаемые программы.
Понятия
Классы
Класс – это шаблон (чертеж), который определяет атрибуты (переменные) и методы (функции) объекта. Из одного класса можно создать сколько угодно объектов. Пример создания класса:
class MyClass:
def __init__(self, x):
self.my_variable = x
def display_variable(self):
print("Моя переменная:", self.my_variable)
MyClass(5).display_variable() # Моя переменная: 5
Объекты
Объект – это экземпляр класса. Он содержит данные, определенные в классе, и может вызывать методы класса. Инициализация класса – это процесс создания объекта класса и инициализации его атрибутов. В Python инициализация выполняется с помощью метода __init__
, который является конструктором класса. В этом методе обычно устанавливаются начальные значения атрибутов объекта.
Когда вы создаете новый объект – экземпляр класса, метод
__init__
автоматически вызывается для инициализации объекта.
В ООП объект является экземпляром класса. В Python практически все является объектами, в т.ч. числа, строки, списки и т.д.
Методы
Методы – это функции, описанные внутри объекта или класса. Они могут изменять состояние объекта и выполнять операции с его данными. Объект вызывает методы с использованием точечной записи object.method()
.
Атрибуты
Атрибуты – это конкретные данные объекта. Это переменные, которые содержат значения, или методы, которые представляют функциональность объекта. Доступ к атрибутам происходит с использованием точечной записи (object.attribute
).
Свойствам предпочтительней давать имена в виде существительных, а методам – в виде глаголов.
Принципы ООП
ООП базируется на трех основных принципах – инкапсуляция, полиморфизм, наследование.
Инкапсуляция
Инкапсуляция в Python – это механизм, позволяющий скрыть атрибуты и методы класса от прямого доступа извне, чтобы обеспечить более безопасное и контролируемое взаимодействие с объектами класса. Инкапсуляция достигается путем использования особых конвенций и соглашений в именовании атрибутов и методов класса:
- Префикс одного подчеркивания (_) перед именем атрибута или метода указывает, что он является “внутренним” и предназначен для использования только внутри класса.
- Префикс двух подчеркиваний (__) перед именем атрибута или метода указывает, что он является “приватным” и недоступным для прямого доступа вне класса.
Наследование
Наследование в Python позволяет создавать новый класс на основе уже существующего класса, заимствуя его свойства и методы. Новый класс, называемый дочерним классом, наследует атрибуты и методы от родительского класса, называемого базовым классом. Это позволяет избежать дублирования кода и повторного использования функциональности. Дочерний класс может также переопределять методы базового класса или добавлять свои собственные методы и атрибуты. Для создания дочернего класса используется следующий синтаксис:
class ChildClass(BaseClass):
# определение дочернего класса
В Python все встроенные и библиотечные классы, а также все созданные разработчиком программы классы прямо или косвенно наследуют единый базовый класс object.
Полиморфизм
Полиморфизм в Python позволяет объектам разных классов обладать одинаковым интерфейсом, что позволяет использовать их взаимозаменяемо. Это означает, что методы могут иметь одинаковые имена, но различную реализацию в разных классах. Полиморфизм позволяет вызывать одинаковые методы на различных объектах без необходимости знать конкретный тип каждого объекта. Например, у разных классов может быть метод с одинаковым именем, но с разной логикой выполнения. При вызове этого метода, Python будет использовать соответствующую реализацию в зависимости от типа объекта.
Создаем свой класс
class Dom:
"""Класс с описанием характеристик дома"""
color = "red"
square = 100
print(Dom.__doc__) # печатаем описание класса
print(Dom.color, Dom.square) # печатаем атрибуты класса
dom2 = Dom() # создаем экземпляр класса
dom3 = Dom() # создаем экземпляр класса
print(type(dom2)) # является экземпляром класса Dom
print(isinstance(dom2, Dom)) # является экземпляром класса Dom
dom3.color = "black" # создаем атрибут экземпляра класса
dom3.floors = 2 # создаем атрибут экземпляра класса
setattr(dom2, "windows", 6) # создаем атрибут экземпляра класса
print(Dom.__dict__) # Все атрибуты класса
print(dom2.__dict__) # Все атрибуты экземпляра класса
print(dom3.__dict__) # Все атрибуты экземпляра класса
d1 = dom3.floors # получаем значение атрибута
print(d1)
d2 = getattr(dom2, "floors", "нет такого атрибута") # получаем значение атрибута
print(d2)
delattr(dom3, "color") # удаляем атрибут
print(dom3.__dict__) # Все атрибуты экземпляра класса
print(dom3.color) # получаем значение атрибута класса Dom
print(hasattr(dom3, "color")) # проверяем наличие атрибута в экземпляре класса или в классе
__doc__
– это специальный атрибут в Python, который содержит строку документации для классов, функций, модулей и других объектов. Атрибут устанавливается во время определения объекта и не может быть изменен позже. Если документация не указана явно, значение атрибута __doc__
будет None
.
__dict__
– это специальный атрибут в Python, который представляет собой словарь, содержащий атрибуты объекта. Словарь __dict__
не содержит атрибутов, определенных в родительских классах.
Функция isinstance()
возвращает True
, если объект является экземпляром любого указанного класса (классов) или его подкласса. Эту функцию часто используется для проверки типа объекта в условных операторах или для реализации полиморфного поведения.
Функция setattr()
– это встроенная функция Python, которая устанавливает значение атрибута объекта. Эта функция полезна в ситуациях, когда имя атрибута хранится в переменной или генерируется динамически.
Функция getattr()
– это встроенная функция Python, которая получает значение атрибута объекта. Эта функция полезна в ситуациях, когда имя атрибута хранится в переменной или генерируется динамически. Если атрибута нет, то возвращается значение заданное в функции по умолчанию.
Функция delattr()
-это встроенная функция Python, которая удаляет атрибут из объекта, если объект позволяет это. При удалении атрибута в родительском классе он не удаляется в дочерних классах.
Функция hasattr()
– это встроенная функция Python, которая проверяет, имеет ли объект заданный атрибут. Возвращает True
, если атрибут существует, иначе False
. Функция полезна для проверки наличия атрибута перед его использованием. Она также может использоваться для проверки наличия динамически сгенерированных атрибутов. При наличия атрибута в родительском классе – возвращает True
.
Создание объекта класса
В каждом классе языка Python есть магические методы, которые начинаются и заканчиваются двумя подчеркиваниями. Нас интересует __init__(self) – инициализатор объекта класса.
Для создания объекта необходимо использовать метод __init__()
. Этот метод инициализирует объект, устанавливая начальные значения его атрибутов. Его основная задача – инициализировать атрибуты экземпляра класса. Метод __init__()
должен принимать хотя бы один параметр – self
.
Конструктор класса – это специальный метод в объектно-ориентированном программировании, который вызывается при создании объекта. В Python конструктором класса является
__init__
. Этот метод вызывается при создании нового объекта класса.
self
Ключевое слово self
в Python – это псевдопеременная, которая ссылается на экземпляр класса в методах этого класса. Оно обеспечивает доступ к атрибутам и методам экземпляра класса (объекта) внутри его класса. Ключевое слово self
должно быть первым параметром в определении метода класса. Внутри метода self
ссылается на экземпляр класса, с которым вызывается данный метод. self
– необязательный параметр, но он является хорошей практикой для ясности кода. self
ссылается только на текущий экземпляр класса.
Необходимо также упомянуть и про магический метод __del__ , который используется для удаления объектов из памяти и освобождения занятых ими ресурсов. Оператор del
в Python используется для удаления объектов из памяти и освобождения занятых ими ресурсов. Создание метода __del__(self)
не является обязательным в классах Python, но его можно определить для очистки любых ресурсов, занимаемых объектом, перед его удалением. Метод __del__
вызывается автоматически, когда счетчик ссылок на объект становится нулевым, что означает, что объект больше не используется и может быть удален из памяти.
Для понимания принципов работы создадим простую программу
class Dom:
"""Класс с описанием характеристик дома"""
def __init__(self, width=6, length=6, color="red"):
self.width = width
self.length = length
self.color = color
def __del__(self):
print(f"удаление экземпляра класса {self}")
def set_description_dom(self, material): # self ссылается на экземпляр класса из которого вызывается этот метод
self.material = material # благодаря self можно создать атрибут экземпляра класса
description_dom = f"Дом имеет характеристики: ширина {self.width}, длина {self.length}. Дом из материала {self.material}."
return description_dom
def get_description_dom(self):
return self.color
domik1 = Dom(7, 12, "blue") # создаем экземпляр класса с заданными атрибутами
print(domik1.__dict__) # выведем на печать все атрибуты экземпляра класса
domik2 = Dom() # создаем экземпляр класса с атрибутами по умолчанию
print(domik2.__dict__) # выведем на печать все атрибуты экземпляра класса
# выведем на печать описание дома с атрибутами - размеры дома + создаем атрибут материала - "кирпич")
print(domik2.set_description_dom("кирпич"))
# получаем и печатаем атрибут экземпляра класса - цвет дома
print(domik1.get_description_dom()) # печатаем атрибуты
print(domik1) # строковое представление экземпляра класса Dom
print(domik2) # строковое представление экземпляра класса Dom
domik1 = 777 # присваиваем новое значение. в этот момент удалится экземпляр класса
print(domik1) # 777
# в конце программы будет удален и domik2 - экземпляр класса Dom
вот то, что получаем в терминале
если внимательно посмотрите на код и вывод в терминале, то все станет очевидным. Как работает __init__, __del__, self теперь должно быть понятным.
Стоит также знать, что существует метод __new__
, который вызывается перед __init__
при создании нового экземпляра класса.
Значки в VSCODE
При написании кода в VScode после обращения к экземпляру класса с точкой появится выпадающий список, в котором по значку “куб” можно понять, что это название метода, а по значку “кирпич в квадратных скобках”, что это название атрибута.