Объектно-ориентированное программирование: классы, объекты, конструктор __init__ и методы
Фундаментальная парадигма ООП: объявление классов, создание объектов, инициализация через конструктор __init__, ключевое слово self, атрибуты и методы экземпляра.
В процедурном программировании данные и функции, обрабатывающие эти данные, разделены: программа представляет собой последовательность инструкций и вызовов процедур. С ростом сложности системы такое разделение приводит к трудноуловимым ошибкам: изменение структуры словаря или кортежа требует переписывания десятков функций по всему проекту.
Объектно-ориентированное программирование (ООП) объединяет состояние (переменные/атрибуты) и поведение (функции/методы) в единую неделимую сущность — объект. Класс является чертежом или шаблоном (blue-print), определяющим структуру будущих объектов, а объект (экземпляр, instance) — конкретным материальным воплощением этого шаблона в оперативной памяти с уникальными значениями полей.
Каждый созданный экземпляр занимает собственный адрес в куче (heap) памяти и хранит ссылку на класс-создатель. Такой подход позволяет мыслить категориями предметной области: "Студент", "БанковскийСчет", "СетевойПакет", делая архитектуру программ расширяемой, надежной и легко поддерживаемой.
Класс (Class)
Объект / Экземпляр (Object / Instance)
Состояние и Поведение
Аналогия чертежа и здания
Класс — это архитектурный чертеж многоэтажного дома. По одному чертежу можно построить десятки реальных зданий (объектов). Чертеж не занимает земельный участок и в нем нельзя жить, но каждый построенный дом имеет конкретный адрес и жителей.
При создании нового объекта интерпретатор Python автоматически выполняет двухуровневый процесс: сначала метод __new, выделяет участок памяти под новый экземпляр, а затем вызывается конструктор инициализации __init, , заполняющий начальное состояние атрибутов.
Параметр self в определении методов класса — это обязательная явная ссылка на текущий конкретный экземпляр, для которого вызывается данный метод. Когда вызывается s1.start(), Python транслирует этот вызов в Server.start(s1). Внутри метода через self.name или self.cpu происходит обращение к атрибутам именно этого объекта, а не соседнего.
Атрибуты экземпляра создаются динамически внутри __init, через присваивание self.attribute = value. В отличие от них, переменные, объявленные на уровне тела класса (вне методов), называются атрибутами класса: они разделяются всеми экземплярами одновременно и расходуют общую ячейку памяти.
Действие 1
Действие 2
Действие 3
Действие 4
Действие 5
В объектной модели Python методы делятся на три категории в зависимости от контекста связывания:
1. Обычные методы экземпляра (Instance methods): принимают self первым аргументом, имеют полный доступ к атрибутам текущего объекта и могут изменять его состояние.
2. Методы класса (@classmethod): принимают cls первым аргументом, имеют доступ только к атрибутам самого класса. Часто используются как фабричные методы (альтернативные конструкторы для парсинга JSON, строк или словарей).
3. Статические методы (@staticmethod): независимые утилитные функции внутри пространства имен класса, не принимающие ни self, ни cls. Они не обращаются к состоянию экземпляра или класса, но логически принадлежат данной сущности.
Грамотное разделение методов по этим трем типам предотвращает утечку глобальных функций и соблюдает принцип высокой связности (High Cohesion).
Когда использовать @classmethod
Если вам нужно создать объект не из отдельных параметров (ip, port), а из готовой строки конфигурации, файла JSON или кортежа, создайте фабричный метод с декоратором @classmethod. Это делает код читаемым и гибким.
Специальные методы, имена которых начинаются и заканчиваются двойным подчеркиванием (double underscore -> dunder), позволяют перегружать стандартные операторы языка Python и встраивать пользовательские классы в экосистему стандартной библиотеки.
Наиболее важными являются методы строкового представления:
- __str, (self): человекочитаемый строковый вид для пользователей, возвращается функциями print() и str().
- __repr, (self): однозначное техническое представление объекта для разработчика и отладки, в идеале такое, чтобы вызов eval(repr(obj)) воссоздавал исходный объект.
Метод __len, (self) позволяет применять к объекту стандартную функцию len(), а __eq, (self, other) перегружает оператор равенства ==. Реализация dunder-методов делает работу с вашими объектами интуитивной для любого Python-разработчика.
