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

Последнее обновление: 04.02.2024

Обычно классы отражают некоторые объекты окружающей действительности. Но иногда нам приходится работать с сущностями, которые не имеют конкретного воплощения. Например, сущность "животное". Есть конкретные животные - кошка, собака и так далее, но животное как таковое не имеет конкретного воплощения. Или сущность "геометрическая фигура". Есть прямоугольник, квадрат, круг, треугольник, но сама по себе геометрическая фигура также не имеет конкретного воплощения. И обычно для описания подобных сущностей применяются абстрактные классы.

В языке Python все инструменты для создания абстрактных классов определены в специальном модуле abc, который надо дополнительно подключать в приложении

import abc

Ключевыми компонентами этого модуля является класс ABC и аннотация @abstractmethod. Класс ABC упрощает создание абстрактного класса, и все определяемые абстрактные классы наследуются от этого класса. Аннотация @abstractmethod предназначеня для создания абстрактного метода.

Абстрактные классы определяются как обычные классы за тем исключением, что они наследуются от класса ABC из модуля abc. Например, определим абстрактный класс геометрической фигуры:

import abc
class Shape(abc.ABC):
    pass

Как правило, абстрактные классы объявляют некоторый общий функционал для классов наследников. Причем некоторый функционал может не иметь никакой реализации - его реализацию должны определить классы-наследники. Подобный функционал оформляется в классе в виде абстрактных методов. Например, класс геометрической фигуры может иметь методы вычисления периметра, площади и т.д. Мы не можем определить общую формулу для вычисления площади всех фигур - для каждой конкретной фигуры принцип вычисления площади может отличаться. Поэтому в классе фигуры мы можем определить метод вычисления площади как абстрактный. Для этого применяется аннотация @abstractmethod из модуля abc:

import abc
class Shape(abc.ABC):
    @abc.abstractmethod 
    def area (self): pass       # площадь фигуры

В данном случае метод area() определен как абстрактный. Так как ему не нужен конкретный функционал, в нем вызывается оператор pass

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

import abc
class Shape(abc.ABC):
    @abc.abstractmethod 
    def area (self): pass       # площадь фигуры

shape = Shape()     # ! Ошибка - так нельзя
print(shape)

Классы-наследники должны реализовать все абстрактные методы абстрактного класса. Например, определим класс прямоугольника:

import abc
class Shape(abc.ABC):
    @abc.abstractmethod 
    def area (self): pass       # площадь фигуры

# класс прямоугольника 
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def area (self): return self.width * self.height
    
rect = Rectangle(30, 50)
print("Rectangle area:", rect.area())   # Rectangle area: 1500 

Здесь класс прямоугольника Rectangle принимает через конструктор ширину и высоту и использует их для вычисления площади в методе area().

Подобным образом можно определить и другие типы фигур. Например, добавим класс круга:

import abc
class Shape(abc.ABC):
    @abc.abstractmethod 
    def area (self): pass       # площадь фигуры

# класс прямоугольника 
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def area (self): return self.width * self.height
    
# класс круга 
class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    def area (self): return self.radius * self.radius * 3.14
    

def print_area(shape):
    print("Area:", shape.area())
    

rect = Rectangle(30, 50)
circle = Circle(30)
print_area(rect)        # Area: 1500
print_area(circle)      # Area: 2826.0

В данном случае для вывода площади фигуры определена функция print_area, которая принимает любую фигуру.

При этом абстрактные классы также могут определять конструктор, атрибуты, неабстрактные методы, которые также могут применяться в классах-наследниках:

import abc
class Shape(abc.ABC):
    def __init__(self, x, y):
        self.x = x
        self.y = y 
        
    @abc.abstractmethod     
    def area (self): pass       # абстрактны метод
    
    def print_point(self):          # неабстрактный метод
        print("X:", self.x, "\tY:", self.y)

# класс прямоугольника 
class Rectangle(Shape):
    def __init__(self, x, y, width, height):
        super().__init__(x, y)
        self.width = width
        self.height = height
    def area (self): return self.width * self.height
    

rect = Rectangle(10, 20, 100, 100)
rect.print_point()      # X: 10   Y: 20

Здесь абстрактный класс Shape через конструктор принимает координаты X и Y для точки, относительно которой создается фигура (например, для прямоугольника это могут быть координаты верхнего левого угла, для круга - центр). И также определен неабстрактный метод print_point, который выводит координаты точки на консоль.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850