08. Расширенные возможности ООП
Расширенные возможности ООП
Описание: Этот урок поможет вам понять, как устроено объектно-ориентированное программирование (ООП) в Python на более глубоком уровне. Вы научитесь правильно применять наследование, скрывать внутренние данные, использовать абстрактные классы и реализовывать гибкое поведение через полиморфизм.1. Напоминание: что такое ООП
ООП — это способ организации кода, при котором программа строится из объектов, у которых есть:- состояние (атрибуты, переменные внутри объекта);
- поведение (методы, которые выполняют действия).
Ключевые принципы ООП:
- Инкапсуляция — скрытие деталей реализации.
- Наследование — использование кода родительских классов.
- Полиморфизм — единый интерфейс для разных типов объектов.
- Абстракция — выделение только сути без деталей.
2. Наследование
Наследование позволяет создавать новый класс на основе существующего.
class User:
def __init__(self, name):
self.name = namedef info(self):
print(f'Пользователь: {self.name}')
class Admin(User): # Наследуем от User
def delete_user(self, user):
print(f'{self.name} удалил пользователя {user.name}')
user1 = User('Анна')
admin = Admin('Сергей')
admin.info() # Использует метод родителя
admin.delete_user(user1)
Вывод:
Пользователь: Сергей
Сергей удалил пользователя Анна
Один класс может наследовать методы и атрибуты другого, а также добавлять свои собственные.
3. Переопределение методов
Если нужно изменить поведение родительского метода — просто переопредели его в дочернем классе:
class User:
def info(self):
print('Обычный пользователь')class Admin(User):
def info(self):
print('Администратор с полными правами')
users = [User(), Admin()]
for u in users:
u.info() # Полиморфизм в действии
Вывод:
Обычный пользователь
Администратор с полными правами
4. Инкапсуляция
Инкапсуляция защищает внутренние данные от прямого доступа.
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance # приватное полеdef deposit(self, amount):
if amount > 0:
self.__balance += amount
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
else:
print('Недостаточно средств!')
def get_balance(self):
return self.__balance
acc = BankAccount('Иван', 100)
acc.deposit(50)
print(acc.get_balance()) # 150
acc.__balance = 999999 # Не изменит реальный баланс!
print(acc.get_balance()) # 150
Двойное подчёркивание делает переменную «приватной», и она становится недоступной напрямую из вне.
5. Свойства (property)
Иногда нужно контролировать доступ к данным, но при этом обращаться к ним как к обычным атрибутам.
class Product:
def __init__(self, price):
self._price = price@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value > 0:
self._price = value
else:
raise ValueError('Цена должна быть положительной')
p = Product(100)
print(p.price)
p.price = 250
print(p.price)
Используйте @property, чтобы сделать код безопаснее и элегантнее.
6. Полиморфизм
Полиморфизм позволяет использовать один и тот же метод для разных типов объектов.
class Dog:
def speak(self):
return 'Гав!'class Cat:
def speak(self):
return 'Мяу!'
animals = [Dog(), Cat()]
for a in animals:
print(a.speak())
Вывод:
Гав!
Мяу!
Один интерфейс — разное поведение. Это и есть полиморфизм.
7. Абстрактные классы
Абстрактные классы задают общий интерфейс, который обязаны реализовать дочерние классы.
from abc import ABC, abstractmethodclass Shape(ABC):
@abstractmethod
def area(self):
pass
class Circle(Shape):
def __init__(self, r):
self.r = r
def area(self):
return 3.14 * self.r ** 2
class Rectangle(Shape):
def __init__(self, w, h):
self.w, self.h = w, h
def area(self):
return self.w * self.h
shapes = [Circle(5), Rectangle(4, 6)]
for s in shapes:
print(s.area())
Вывод:
78.5
24
- Абстрактный класс нельзя создать напрямую.
- Он определяет обязательные методы для наследников.
8. Множественное наследование
Класс может наследоваться сразу от нескольких родителей.
class Logger:
def log(self, message):
print(f'[LOG]: {message}')class Saver:
def save(self, filename):
print(f'Сохраняем данные в {filename}')
class Report(Logger, Saver):
def generate(self):
self.log('Создаём отчёт...')
self.save('report.txt')
r = Report()
r.generate()
Вывод:
[LOG]: Создаём отчёт...
Сохраняем данные в report.txt
9. Пример мини-проекта: система уведомлений
Создадим систему, где разные типы уведомлений (email, SMS, push) реализуют общий интерфейс.
from abc import ABC, abstractmethodclass Notifier(ABC):
@abstractmethod
def send(self, message):
pass
class EmailNotifier(Notifier):
def send(self, message):
print(f'Отправлено на e-mail: {message}')
class SMSNotifier(Notifier):
def send(self, message):
print(f' SMS отправлено: {message}')
class PushNotifier(Notifier):
def send(self, message):
print(f' Push-уведомление: {message}')
# Используем полиморфизм
notifiers = [EmailNotifier(), SMSNotifier(), PushNotifier()]
for n in notifiers:
n.send('Обновление системы успешно установлено!')
Вывод:
Отправлено на e-mail: Обновление системы успешно установлено!
SMS отправлено: Обновление системы успешно установлено!
Push-уведомление: Обновление системы успешно установлено!
10. Лучшие практики ООП
- Используйте инкапсуляцию, чтобы защитить внутренние данные.
- Не злоупотребляйте наследованием — применяйте его, если действительно нужно.
- Используйте абстрактные классы и интерфейсы для расширяемости кода.
- Пишите читаемые имена методов и классов — это часть хорошего дизайна.
Итоги урока
Теперь вы умеете:- Применять наследование и переопределение методов.
- Использовать инкапсуляцию и property для защиты данных.
- Создавать абстрактные классы и интерфейсы.
- Использовать полиморфизм в реальных задачах.