Гид по технологиям

Объектно-ориентированное программирование в Python

5 min read Программирование Обновлено 17 Dec 2025
OOP в Python: классы, объекты и наследование
OOP в Python: классы, объекты и наследование

Два человека сидят лицом друг к другу; на экране одного из ноутбуков видно логотип Python

TL;DR

Python отлично подходит для изучения и применения объектно-ориентированного программирования. Классы оформляют структуру данных и поведение, объекты — конкретные экземпляры. ООП упрощает поддержку кода, повторное использование и расширяемость, но иногда функциональный или процедурный подходы лучше.

Краткое содержание

  • Что такое ООП и зачем оно нужно в Python
  • Как объявлять классы и создавать объекты
  • Атрибуты, методы, наследование и проверки типа
  • Практические рекомендации, тесты приёмки и чек-листы для ролей
  • Когда ООП не подходит и альтернативы

Что такое объектно-ориентированное программирование

Объектно-ориентированное программирование — парадигма, где программные сущности моделируются как объекты: они содержат данные и поведение. Класс — шаблон для объектов. Объект — конкретный экземпляр класса.

Опорные принципы ООП:

  • Инкапсуляция — объединять данные и поведение и скрывать реализацию.
  • Абстракция — показывать только необходимые детали.
  • Наследование — переиспользовать код базовых классов.
  • Полиморфизм — использовать единый интерфейс для разных типов.

1-строчная дефиниция термина:

  • Класс: шаблон структуры и поведения.
  • Объект: экземпляр класса с конкретными значениями.

Важно: ООП помогает организовать сложные системы, но не является универсальным решением для всех задач.

Почему OOP в Python удобен

Python имеет лаконичный синтаксис, явную поддержку классов и динамическую систему типов. Благодаря этому:

  • Код читается быстрее.
  • Проще тестировать и расширять программы.
  • Легко создавать иерархии типов и переопределять поведение.

Однако OOP не всегда оптимально по производительности или простоте для очень простых задач. См. раздел «Когда OOP не подходит».

Как объявить класс в Python

Чтобы объявить класс, используйте ключевое слово class и имя класса. Пример базового класса:

class MyClass:
    x = 2

p1 = MyClass()
print(p1.x)

Пример из предметной области — класс для описания штанов. Мы назовём его Pant.

class Pant:
    # Определим свойства и зададим им None по умолчанию
    size = None
    onsale = None
    material = None
    price = None

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

Как создать объект и инициализатор

Инициализатор в Python называется init. Он вызывается при создании объекта и задаёт начальные значения.

class Pant:
    # Инициализатор экземпляра
    def __init__(self, size, onsale, material, price):
        self.size = size
        self.onsale = onsale
        self.material = material
        self.price = price

# Создаём экземпляр класса Pant
jeans = Pant(11, False, 'Denim', 81)

Пояснение:

  • self указывает на текущий экземпляр.
  • Аргументы конструктора задают свойства экземпляра.

Атрибуты и методы: поведение и данные

Есть два типа атрибутов:

  • Атрибуты класса — общие для всех объектов класса.
  • Атрибуты экземпляра — уникальны для каждого объекта.

Пример методов экземпляра:

class Pant:
    def __init__(self, size, onsale, material, price):
        self.size = size
        self.onsale = onsale
        self.material = material
        self.price = price

    def printinfo(self):
        return f'This pair of pants is size {self.size}, made of {self.material}, and costs {self.price}'

    def putonsale(self):
        self.onsale = True

jeans = Pant(11, False, 'Denim', 81)
print(jeans.printinfo())
jeans.putonsale()
print(jeans.onsale)

Заметка: методы используют self, чтобы работать с данными конкретного объекта.

Наследование: расширение классов

Наследование позволяет создавать подклассы, которые расширяют или модифицируют поведение базового класса.

# Leggings наследует свойства и методы Pant
class Leggings(Pant):
    def __init__(self, size, onsale, material, price, elasticity):
        Pant.__init__(self, size, onsale, material, price)
        self.elasticity = elasticity

    def printinfo(self):
        return f'This pair of leggings is size {self.size}, made of {self.material}, and costs {self.price}'

leggings = Leggings(11, False, 'Leather', 42, True)
print(leggings.printinfo())

Преимущества наследования:

  • Переиспользование кода.
  • Легкая расширяемость.
  • Локализация изменений.

Проверка типа с помощью isinstance

isinstance(obj, Class) возвращает True, если объект является экземпляром класса или его подкласса.

class Pant:
    None

class Leggings(Pant):
    None

pants = Pant()
leggings = Leggings()

print(isinstance(leggings, Pant))   # True
print(isinstance(pants, Leggings))  # False

Это удобно для безопасной обработки входных данных и выполнения полиморфных операций.

Примеры использования и шаблоны проектирования

ОП позволяет удобно строить следующие паттерны:

  • Фабрики и фабричные методы для создания объектов.
  • Стратегии для смены алгоритмов во время выполнения.
  • Декораторы для расширения поведения объектов без изменения класса.

Примечание: многие паттерны в Python реализуются проще, чем в языках со статической типизацией.

Когда ООП не подходит и альтернативы

Контрпримеры и случаи, когда OOP повышает сложность:

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

Альтернативы:

  • Процедурный стиль для линейных задач.
  • Функциональный стиль для преобразований данных (иммутабельность, чистые функции).
  • Data-oriented design, когда ключевым является плотное хранение структурированных массивов.

Мини-методология проектирования классов

  1. Определите сущности предметной области и их ответственность.
  2. Придерживайтесь принципа единственной ответственности для каждого класса.
  3. Сначала опишите публичный интерфейс, затем внутреннюю реализацию.
  4. Пишите модульные тесты для каждого метода.
  5. Используйте композицию вместо наследования, когда это проще и понятнее.

Быстрый чек-лист проектировщика:

  • Нужен ли класс или достаточно функции?
  • Можно ли разбить ответственность на несколько меньших классов?
  • Есть ли естественный интерфейс для тестирования?

Критерии приёмки для класса Pant

  • Конструктор задаёт size, onsale, material и price.
  • Метод printinfo возвращает строку с размером, материалом и ценой.
  • Метод putonsale устанавливает onsale в True.
  • Для подклассов реализована корректная работа наследования и переопределения методов.

Тестовые случаи (acceptance):

  • Создать Pant с конкретными параметрами и проверить доступ к каждому атрибуту.
  • Вызвать printinfo и проверить содержание строки.
  • Вызвать putonsale и проверить, что onsale стало True.
  • Создать Leggings, проверить, что isinstance(leggings, Pant) равно True и printinfo работает.

Чек-листы по ролям

Разработчик-начинающий:

  • Понимаю разницу между классом и объектом.
  • Умею писать init и методы экземпляра.
  • Пишу простые тесты для класса.

Разработчик-средний:

  • Применяю композицию и наследование осознанно.
  • Знаю, когда использовать свойства @property.
  • Пишу документацию для публичного API класса.

Техлид:

  • Проектирую доменную модель с учётом расширяемости.
  • Контролирую границы ответственности и зависимости между классами.
  • Устанавливаю правила кодстайла и проверки типов (mypy, type hints).

Безопасность и приватность

  • Для приватных данных используйте соглашение _single_underscore или __double_underscore по необходимости, но помните, что в Python доступ при желании возможен.
  • Не храните секреты в полях объектов без шифрования.
  • Для публичных API документация важнее технических ограничений.

Примеры расширения и альтернативная реализация

Композиция вместо наследования:

class Elasticity:
    def __init__(self, level):
        self.level = level

class PantsWithElasticity:
    def __init__(self, pant, elasticity):
        self.pant = pant
        self.elasticity = elasticity

p = Pant(11, False, 'Denim', 81)
e = Elasticity(True)
pe = PantsWithElasticity(p, e)

Такой подход позволяет менять поведение во время выполнения без сложных иерархий.

Decision flowchart

flowchart TD
  A[Нужна ли модель с состоянием?] -->|Да| B[Использовать класс]
  A -->|Нет| C[Использовать функции]
  B --> D[Будет ли наследование?]
  D -->|Да| E[Спроектировать базовый класс]
  D -->|Нет| F[Использовать композицию]
  C --> G[Функциональное и тестируемое]

Глоссарий в одну строку

  • Класс: шаблон объекта.
  • Объект: экземпляр класса.
  • Метод: функция внутри класса.
  • Атрибут: свойство объекта.
  • Наследование: механизм повторного использования кода.

Быстрые советы и лучшие практики

  • Пишите короткие методы.
  • Предпочитайте композицию, когда поведение можно комбинировать.
  • Документируйте публичный интерфейс класса.
  • Добавляйте unit-тесты для граничных случаев.

Сводка

  • OOP в Python делает код структурированным, читаемым и расширяемым.
  • Используйте классы для моделирования сущностей с состоянием и поведением.
  • Не злоупотребляйте наследованием; помните про композицию.

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

Примечание: все примеры в статье используют базовый Python без сторонних библиотек.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как создать тред в Discord — пошагово
Руководство

Как создать тред в Discord — пошагово

Hand Tracking на Oculus Quest — включение и жесты
VR

Hand Tracking на Oculus Quest — включение и жесты

Переключение между экранами в Windows
Windows

Переключение между экранами в Windows

Как заблокировать сайт в Firefox
Браузеры

Как заблокировать сайт в Firefox

Как посмотреть и отключить историю ссылок в Facebook
Социальные сети

Как посмотреть и отключить историю ссылок в Facebook

Как скачать OneDrive для Windows 7
Инструкции

Как скачать OneDrive для Windows 7