Разбери основы на конкретном примере!
В Python абстрактные базовые классы предоставляют схему конкретных классов. Они не содержат реализации. Вместо этого они предоставляют интерфейс и обеспечивают правильную реализацию производных конкретных классов.
- Невозможно создать экземпляры абстрактных базовых классов. Вместо этого они наследуются и расширяются конкретными подклассами.
- Подклассы, производные от определенного абстрактного базового класса, должны реализовывать методы и свойства, предоставленные в этом абстрактном базовом классе. В противном случае во время создания объекта возникает ошибка.
Напишем код Python3, содержащий простые примеры реализации абстрактных базовых классов:
from abc import ABCMeta, abstractmethod class AbstactClassCSV(metaclass = ABCMeta): def __init__(self, path, file_name): self._path = path self._file_name = file_name @property @abstractmethod def path(self): pass @path.setter @abstractmethod def path(self,value): pass @property @abstractmethod def file_name(self): pass @file_name.setter @abstractmethod def file_name(self,value): pass @abstractmethod def display_summary(self): pass
Определение абстрактного базового класса
Python предоставляет модуль abc для определения абстрактного базового класса. Нам нужно импортировать метакласс ABCMeta и назначить его абстрактному классу, который мы хотим определить.
from abc import ABCMeta, abstractmethod class AbstactClassCSV(metaclass = ABCMeta): ..... .....
Внутри абстрактного базового класса мы заставляем подклассы реализовывать свойства path и file_name с помощью декоратора @abstractmethod. Обратите внимание, что свойства не реализованы и пусты, поскольку абстрактные классы используются только для определения интерфейса.
@property @abstractmethod def path(self): pass @path.setter @abstractmethod def path(self,value): pass @property @abstractmethod def file_name(self): pass @file_name.setter @abstractmethod def file_name(self,value): pass
Опять же, с помощью декоратора @abstractmethod мы можем определить абстрактный метод и заставить подклассы реализовать метод display_summary (self).
@abstractmethod def display_summary(self): pass
На этом этапе, если мы попытаемся создать экземпляр объекта абстрактного класса AbstactClassCSV, мы получим ошибку.
abc_instantiation = AbstactClassCSV("/Users/erdemisbilen/Lessons/", "data_by_genres.csv") Output: Traceback (most recent call last): File "ABCExample.py", line 119, in <module> abc_instantiation = AbstactClassCSV("/Users/erdemisbilen/Lessons/", "data_by_genres.csv") TypeError: Can't instantiate abstract class AbstactClassCSV with abstract methods display_summary, file_name, path
Создание конкретного подкласса, производного от абстрактного базового класса
Теперь, когда у нас есть абстрактный базовый класс (AbstactClassCSV), мы можем создать наш подкласс путем наследования.
Ниже я создал конкретный класс CSVGetInfo, унаследовав его от абстрактного класса AbstactClassCSV. Следовательно, я должен строго следовать интерфейсу, предоставляемому абстрактным классом, и правильно реализовать все продиктованные методы и свойства в моем конкретном подклассе.
class CSVGetInfo(AbstactClassCSV): """ This class displays the summary of the tabular data contained in a CSV file """ @property def path(self): """ The docstring for the path property """ print("Getting value of path") return self._path @path.setter def path(self,value): if '/' in value: self._path = value print("Setting value of path to {}".format(value)) else: print("Error: {} is not a valid path string".format(value)) data_by_genres = CSVGetInfo("/Users/erdemisbilen/Lessons/", "data_by_genres.csv") Output: Traceback (most recent call last): File "ABCExample.py", line 103, in <module> data_by_genres = CSVGetInfo("/Users/erdemisbilen/Lessons/", "data_by_genres.csv") TypeError: Can't instantiate abstract class CSVGetInfo with abstract methods display_summary, file_name
Чтобы продемонстрировать этот случай, я определил только свойство path и оставил свойства file_name и display_summary не реализованными.
Если я попытаюсь создать экземпляр объекта CSVGetInfo в таком состоянии , возникнет указанная выше ошибка.
Вот как абстрактные классы предотвращают неправильное определение подкласса.
class CSVGetInfo(AbstactClassCSV): """ This class displays the summary of the tabular data contained in a CSV file """ @property def path(self): """ The docstring for the path property """ print("Getting value of path") return self._path @path.setter def path(self,value): if '/' in value: self._path = value print("Setting value of path to {}".format(value)) else: print("Error: {} is not a valid path string".format(value)) @property def file_name(self): """ The docstring for the file_name property """ print("Getting value of file_name") return self._file_name @file_name.setter def file_name(self,value): if '.' in value: self._file_name = value print("Setting value of file_name to {}".format(value)) else: print("Error: {} is not a valid file name".format(value)) def display_summary(self): data = pd.read_csv(self._path + self._file_name) print(self._file_name) print(data.info())
Поскольку мы определили все необходимые свойства и методы, продиктованные абстрактным классом выше, теперь мы можем создавать и использовать объекты производного подкласса CSVGetInfo.
Ключевые выводы
- Абстрактные базовые классы отделяют интерфейс от реализации.
- Они гарантируют, что производные классы реализуют методы и свойства, продиктованные абстрактным базовым классом.
- Абстрактные базовые классы отделяют интерфейс от реализации. Они определяют общие методы и свойства, которые должны использоваться в подклассах. Реализация осуществляется конкретными подклассами, в которых мы можем создавать объекты, которые могут обрабатывать задачи.
- Они помогают избежать ошибок и упрощают обслуживание иерархий классов, предоставляя строгий рецепт для создания подклассов.
Заключение
В этом посте я объяснил основы абстрактных базовых классов в Python.
Код в этом посте доступен в моем репозитории GitHub.
Надеюсь, этот пост был вам полезен.
Спасибо за чтение!