Абстрактные классы и методы
Часть раздела Объектно-ориентированное программирование путешествия по Python на Coddy. Урок 25 из 64.
Абстрактные классы — это классы, экземпляры которых нельзя создать напрямую и которые содержат абстрактные методы, реализовать которые должны подклассы.
Представь себе форму: абстрактный класс — это обязательный шаблон формы, в котором одни поля обязательны (абстрактные методы), а другие — необязательны (конкретные методы). Ты не можешь отправить сам шаблон — сначала нужно заполнить все обязательные поля. Точно так же нельзя создавать экземпляры абстрактного класса, пока все абстрактные методы не будут реализованы в подклассе.
Импортируй модуль abc, чтобы создавать абстрактные классы:
from abc import ABC, abstractmethodСоздайте абстрактный класс с абстрактными методами:
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
def describe(self):
return "This is a shape" # Конкретный метод (имеет реализацию)Декоратор @abstractmethod помечает методы, которые подклассы должны реализовать, — это «обязательные поля» вашей формы. Обычные методы, такие как describe(), могут иметь реализацию и наследуются без изменений — это «заполненные заранее поля».
Зачем использовать абстрактные классы? Они задают контракт. Создавая класс Shape, ты говоришь: «каждая фигура ОБЯЗАНА уметь вычислять свою площадь и периметр». Это предотвращает ошибки, которые могут возникнуть, если забыть реализовать важные методы.
Попробуй создать экземпляр абстрактного класса:
# Это вызовет ошибку:
# shape = Shape() # TypeError: Невозможно создать экземпляр абстрактного классаЭта ошибка возникает намеренно — это похоже на попытку отправить пустую форму. Python говорит: «Ты ещё не заполнил обязательные поля (методы площади и периметра)!»
Создай конкретный подкласс, реализующий все абстрактные методы:
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
def perimeter(self):
return 2 * 3.14 * self.radiusТеперь мы «заполнили все обязательные поля» — реализовали и area(), и perimeter(). Класс Circle теперь является полным конкретным классом, экземпляр которого можно создать.
Теперь ты можешь создавать экземпляры конкретного класса:
circle = Circle(5)
print(circle.area())
print(circle.perimeter())
print(circle.describe()) # Унаследованный конкретный методСоздай ещё один конкретный подкласс:
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width self.height
def perimeter(self):
return 2 * (self.width + self.height)
rectangle = Rectangle(4, 6)
print(rectangle.area())
print(rectangle.perimeter())Вывод:
78.5
31.400000000000002
This is a shape
24
20Абстрактные классы определяют контракт, которому должны следовать подклассы. Используй ABC и @abstractmethod, чтобы создавать абстрактные классы. Подклассы должны реализовать все абстрактные методы, иначе они тоже будут абстрактными. Это обеспечивает единообразие и предотвращает неполные реализации.
Задание
СреднеВ этом задании ты реализуешь систему обработки платежей.
Тебе нужно завершить реализацию в следующих файлах:
paymentmethod.py— абстрактный базовый класс с логикой проверкиcreditcard.py— реализация оплаты кредитной картойpaypal.py— реализация оплаты через PayPal
Следуй комментариям TODO в каждом файле, чтобы реализовать требуемую функциональность. Комментарии помогут тебе шаг за шагом создать абстрактные методы, реализовать конкретные подклассы и установить правильные связи импорта между файлами.
Файл driver.py содержит тесты, которые проверят правильность твоей реализации, обрабатывая различные сценарии оплаты и отображая соответствующие сведения для каждого способа оплаты.
Попробуйте сами
from creditcard import CreditCard
from paypal import PayPal
# Проверьте реализации — НЕ ИЗМЕНЯЙТЕ ЭТОТ ТЕСТОВЫЙ КОД
cc = CreditCard("1234567890123456")
pp = PayPal("user@example.com")
# Обработайте допустимые платежи
if cc.validate(100):
print(cc.process_payment(100))
print(cc.payment_details())
if pp.validate(200):
print(pp.process_payment(200))
print(pp.payment_details())
# Попробуйте указать недопустимую сумму
if not pp.validate(0):
print("Invalid payment amount")
# Если убрать знак комментария, это вызовет ошибку:
# pm = PaymentMethod() # Нельзя создать экземпляр абстрактного классаВ этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Введение в ООПВнешние файлыКлассы и объектыПараметр selfМетодыАтрибутыМетод-конструктор (__init__)Повторение — простой калькулятор4Наследование
Основы наследованияФункция super()Переопределение методовМножественное наследованиеПорядок разрешения методовПовторение: иерархия сотрудников7Специальные методы
Введение в магические методыПерегрузка операторовМагические методы контейнеровПовторение — пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн «Одиночка»Паттерн «Фабрика»Паттерн «Наблюдатель»Паттерн «Стратегия»2Декораторы
Введение в декораторыДекоратор свойстваДекоратор статического методаДекоратор метода класса5Полиморфизм
Переопределение методов: повторениеУтиная типизацияАбстрактные классы и методыПроектирование интерфейсовПовторение — калькулятор фигур8Продвинутые концепции ООП
Композиция и наследованиеМиксиныСтатические методы и методы классаДекораторы классовМенеджеры контекста11Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»3Свойства классов
Переменные экземпляра и классаДекораторы свойствПриватные атрибутыПовторение — менеджер банковского счёта6Инкапсуляция
Публичные, защищённые и приватные членыМодификаторы доступаСокрытие информацииПродвинутые декораторы свойствПовторение — система учёта студентов12Проект: Система управления библиотекой
Обзор проектаКлассы книг и пользователейСистема выдачи книгФункция поискаИнтерфейс администратораТестирование и интеграцияПотренируйтесь самостоятельно: Онлайн-компилятор Python