← Назад к вопросам

Как создать абстрактный класс?

1.0 Junior🔥 121 комментариев
#Python Core#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как создать абстрактный класс

Абстрактный класс — это класс, который не может быть инстанцирован (создана переменная с его типом), а служит шаблоном для наследующих его классов. В Python для создания абстрактных классов используется модуль abc (Abstract Base Classes).

Базовый синтаксис

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_sound(self):
        pass
    
    @abstractmethod
    def move(self):
        pass
    
    # Обычный метод (не абстрактный)
    def description(self):
        return f"I am a {self.__class__.__name__}"

# Попытка создать экземпляр абстрактного класса
# animal = Animal()  # TypeError: Can't instantiate abstract class

# Правильно: создать конкретный класс
class Dog(Animal):
    def make_sound(self):
        return "Woof!"
    
    def move(self):
        return "Running on four legs"

dog = Dog()
print(dog.make_sound())      # Woof!
print(dog.description())     # I am a Dog
print(dog.move())            # Running on four legs

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

Абстрактный метод — это метод, который должен быть переопределён в подклассе:

from abc import ABC, abstractmethod

class Vehicle(ABC):
    @abstractmethod
    def start(self):
        """Запустить транспортное средство"""
        pass
    
    @abstractmethod
    def stop(self):
        """Остановить транспортное средство"""
        pass

class Car(Vehicle):
    def start(self):
        return "Car engine started"
    
    def stop(self):
        return "Car engine stopped"

class Bicycle(Vehicle):
    def start(self):
        return "Start pedaling"
    
    def stop(self):
        return "Stop pedaling"

car = Car()
print(car.start())      # Car engine started
print(car.stop())       # Car engine stopped

bike = Bicycle()
print(bike.start())     # Start pedaling

Абстрактные свойства (properties)

Можно сделать абстрактным и свойство:

from abc import ABC, abstractmethod

class Shape(ABC):
    @property
    @abstractmethod
    def area(self):
        pass
    
    @property
    @abstractmethod
    def perimeter(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    @property
    def area(self):
        return 3.14159 * self.radius ** 2
    
    @property
    def perimeter(self):
        return 2 * 3.14159 * self.radius

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    @property
    def area(self):
        return self.width * self.height
    
    @property
    def perimeter(self):
        return 2 * (self.width + self.height)

circle = Circle(5)
print(f"Circle area: {circle.area:.2f}")

rect = Rectangle(4, 6)
print(f"Rectangle area: {rect.area}")

Класс с методом по умолчанию

Абстрактный метод может иметь реализацию по умолчанию:

from abc import ABC, abstractmethod

class Logger(ABC):
    @abstractmethod
    def log(self, message):
        """Логировать сообщение (по умолчанию добавляем префикс)"""
        print(f"[LOG] {message}")

class FileLogger(Logger):
    def log(self, message):
        # Вызываем реализацию родителя
        super().log(message)
        # Добавляем свою логику
        with open('log.txt', 'a') as f:
            f.write(f"{message}\n")

class ConsoleLogger(Logger):
    def log(self, message):
        # Переопределяем полностью
        print(f"[CONSOLE] {message}")

file_logger = FileLogger()
file_logger.log("Something happened")  # Вызывает и родителя, и свою логику

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

Можно сделать абстрактным и classmethod:

from abc import ABC, abstractmethod

class DatabaseDriver(ABC):
    @classmethod
    @abstractmethod
    def connect(cls, connection_string):
        pass
    
    @abstractmethod
    def execute(self, query):
        pass

class PostgresDriver(DatabaseDriver):
    @classmethod
    def connect(cls, connection_string):
        return f"Connected to PostgreSQL: {connection_string}"
    
    def execute(self, query):
        return f"Executing: {query}"

class MySQLDriver(DatabaseDriver):
    @classmethod
    def connect(cls, connection_string):
        return f"Connected to MySQL: {connection_string}"
    
    def execute(self, query):
        return f"MySQL query: {query}"

print(PostgresDriver.connect("localhost:5432"))
mysql = MySQLDriver()
print(mysql.execute("SELECT *"))

Проверка на абстрактность

Mожно проверить, является ли класс абстрактным:

from abc import ABC, abstractmethod

class Base(ABC):
    @abstractmethod
    def method(self):
        pass

class Concrete(Base):
    def method(self):
        return "implemented"

print(hasattr(Base, '__abstractmethods__'))  # True
print(Base.__abstractmethods__)  # frozenset({'method'})

print(hasattr(Concrete, '__abstractmethods__'))  # False

Практический пример: ORM

from abc import ABC, abstractmethod
from typing import List, Generic, TypeVar

T = TypeVar('T')

class Repository(ABC, Generic[T]):
    """Интерфейс для хранилища данных"""
    
    @abstractmethod
    def find_by_id(self, id: int) -> T:
        pass
    
    @abstractmethod
    def find_all(self) -> List[T]:
        pass
    
    @abstractmethod
    def save(self, entity: T) -> None:
        pass
    
    @abstractmethod
    def delete(self, id: int) -> None:
        pass

class User:
    def __init__(self, id: int, name: str):
        self.id = id
        self.name = name

class UserRepository(Repository[User]):
    def __init__(self):
        self.users = {}
    
    def find_by_id(self, id: int) -> User:
        return self.users.get(id)
    
    def find_all(self) -> List[User]:
        return list(self.users.values())
    
    def save(self, entity: User) -> None:
        self.users[entity.id] = entity
    
    def delete(self, id: int) -> None:
        del self.users[id]

repo = UserRepository()
user = User(1, "Alice")
repo.save(user)
print(repo.find_by_id(1).name)  # Alice

Старый способ (не используется)

До введения ABC в Python 2.6, использовался следующий подход:

class OldStyle:
    def abstract_method(self):
        raise NotImplementedError("Subclasses must implement this")

class Implementation(OldStyle):
    def abstract_method(self):
        return "Implemented"

Этот способ работает, но менее явный и не предотвращает создание экземпляра базового класса.

Различие между ABC и обычным классом

from abc import ABC, abstractmethod

# ABC подход (правильный)
class GoodBase(ABC):
    @abstractmethod
    def required_method(self):
        pass

# Обычный класс с проверкой (плохой)
class BadBase:
    def required_method(self):
        raise NotImplementedError()

# GoodBase() → TypeError: Can't instantiate
# BadBase() → создаётся (ошибка будет позже)

bad = BadBase()
# Ошибка только при вызове метода
bad.required_method()  # NotImplementedError

Заключение

Для создания абстрактного класса в Python:

  1. Импортируй from abc import ABC, abstractmethod
  2. Наследуй класс от ABC
  3. Помечай абстрактные методы декоратором @abstractmethod
  4. Реализуй все абстрактные методы в подклассах
  5. Используй для определения интерфейсов и контрактов

Абстрактные классы помогают:

  • Определить контракт для подклассов
  • Предотвратить создание неполных классов
  • Сделать код более типизированным и понятным
  • Реализовать паттерны как Strategy, Template Method и т.д.