Menu
CoddyTech

Абстрактные классы и методы

Часть раздела Объектно-ориентированное программирование путешествия по 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, чтобы создавать абстрактные классы. Подклассы должны реализовать все абстрактные методы, иначе они тоже будут абстрактными. Это обеспечивает единообразие и предотвращает неполные реализации.

challenge icon

Задание

Средне

В этом задании ты реализуешь систему обработки платежей.

Тебе нужно завершить реализацию в следующих файлах:

  • 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()  # Нельзя создать экземпляр абстрактного класса
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Python