abc.md
1> **Источник:** https://python-all.ru/3.5/library/abc.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 29.7. [`abc`](https://python-all.ru/3.5/library/abc.html#module-abc) – Абстрактные базовые классы89**Исходный код:** [Lib/abc.py](https://python-all.ru/src/3.5/Lib/abc.py)1011---1213Этот модуль предоставляет инфраструктуру для определения [абстрактных базовых классов](https://python-all.ru/3.5/glossary.html#term-abstract-base-class) (ABC) в Python, как описано в [**PEP 3119**](https://python-all.ru/3.5/library/abc.html); см. PEP для информации о том, почему это было добавлено в Python. (См. также [**PEP 3141**](https://python-all.ru/3.5/library/abc.html) и модуль [`numbers`](https://python-all.ru/3.5/library/numbers.html#module-numbers) относительно иерархии типов для чисел на основе ABC.)1415Модуль [`collections`](https://python-all.ru/3.5/library/collections.html#module-collections) содержит несколько конкретных классов, которые наследуются от ABC; их, конечно, можно наследовать дальше. Кроме того, подмодуль [`collections.abc`](https://python-all.ru/3.5/library/collections.abc.html#module-collections.abc) содержит некоторые ABC, которые можно использовать для проверки, предоставляет ли класс или экземпляр определённый интерфейс, например, является ли он хешируемым или отображением.1617Этот модуль предоставляет следующие классы:1819#### `class abc.ABCMeta`2021Метакласс для определения абстрактных базовых классов (ABC).2223Используйте этот метакласс для создания ABC. ABC может быть напрямую унаследован, а затем действует как примесь (mix-in). Также можно регистрировать несвязанные конкретные классы (даже встроенные классы) и несвязанные ABC как «виртуальные подклассы» – они и их потомки будут считаться подклассами регистрирующего ABC встроенной функцией [`issubclass()`](https://python-all.ru/3.5/library/functions.html#issubclass), но регистрирующий ABC не появится в их MRO (порядке разрешения методов), и реализации методов, определённые регистрирующим ABC, не будут вызываемыми (даже через [`super()`](https://python-all.ru/3.5/library/functions.html#super)). [\[1\]](https://python-all.ru/3.5/library/abc.html#id2)2425Классы, созданные с метаклассом [`ABCMeta`](https://python-all.ru/3.5/library/abc.html#abc.ABCMeta), имеют следующий метод:2627#### `register(subclass)`2829Регистрирует *подкласс* как «виртуальный подкласс» этого ABC. Например:3031```python32from abc import ABCMeta3334class MyABC(metaclass=ABCMeta):35 pass3637MyABC.register(tuple)3839assert issubclass(tuple, MyABC)40assert isinstance((), MyABC)41```4243Изменено в версии 3.3: Возвращает зарегистрированный подкласс, что позволяет использовать его в качестве декоратора класса.4445Изменено в версии 3.4: Для обнаружения вызовов [`register()`](https://python-all.ru/3.5/library/abc.html#abc.ABCMeta.register) можно использовать функцию [`get_cache_token()`](https://python-all.ru/3.5/library/abc.html#abc.get_cache_token).4647Также можно переопределить этот метод в абстрактном базовом классе:4849#### `__subclasshook__(subclass)`5051(Должен быть определён как метод класса.)5253Проверяет, считается ли *подкласс* подклассом этого ABC. Это означает, что можно дополнительно настраивать поведение `issubclass` без необходимости вызывать [`register()`](https://python-all.ru/3.5/library/abc.html#abc.ABCMeta.register) для каждого класса, который требуется считать подклассом ABC. (Этот метод класса вызывается из метода `__subclasscheck__()` ABC.)5455Этот метод должен возвращать `True`, `False` или `NotImplemented`. Если он возвращает `True`, то *подкласс* считается подклассом этого ABC. Если он возвращает `False`, то *подкласс* не считается подклассом этого ABC, даже если бы он обычно им был. Если он возвращает `NotImplemented`, проверка на подкласс продолжается обычным механизмом.5657Для демонстрации этих концепций посмотрите на следующий пример определения ABC:5859```python60class Foo:61 def __getitem__(self, index):62 ...63 def __len__(self):64 ...65 def get_iterator(self):66 return iter(self)6768class MyIterable(metaclass=ABCMeta):6970 @abstractmethod71 def __iter__(self):72 while False:73 yield None7475 def get_iterator(self):76 return self.__iter__()7778 @classmethod79 def __subclasshook__(cls, C):80 if cls is MyIterable:81 if any("__iter__" in B.__dict__ for B in C.__mro__):82 return True83 return NotImplemented8485MyIterable.register(Foo)86```8788ABC `MyIterable` определяет стандартный метод итерируемых объектов, [`__iter__()`](https://python-all.ru/3.5/library/stdtypes.html#iterator.__iter__), как абстрактный метод. Приведённую здесь реализацию всё ещё можно вызывать из подклассов. Метод `get_iterator()` также является частью абстрактного базового класса `MyIterable`, но его не обязательно переопределять в неабстрактных производных классах.8990The [`__subclasshook__()`](https://python-all.ru/3.5/library/abc.html#abc.ABCMeta.__subclasshook__) class method defined here says that any class that has an [`__iter__()`](https://python-all.ru/3.5/library/stdtypes.html#iterator.__iter__) method in its [`__dict__`](https://python-all.ru/3.5/library/stdtypes.html#object.__dict__) (or in that of one of its base classes, accessed via the [`__mro__`](https://python-all.ru/3.5/library/stdtypes.html#class.__mro__) list) is considered a `MyIterable` too.9192Наконец, последняя строка делает `Foo` виртуальным подклассом `MyIterable`, даже если он не определяет метод [`__iter__()`](https://python-all.ru/3.5/library/stdtypes.html#iterator.__iter__) (он использует старый протокол итерирования, определённый через [`__len__()`](https://python-all.ru/3.5/reference/datamodel.html#object.__len__) и [`__getitem__()`](https://python-all.ru/3.5/reference/datamodel.html#object.__getitem__)). Обратите внимание, что это не сделает `get_iterator` доступным в качестве метода `Foo`, поэтому он предоставляется отдельно.9394#### `class abc.ABC`9596Вспомогательный класс, метаклассом которого является [`ABCMeta`](https://python-all.ru/3.5/library/abc.html#abc.ABCMeta). С помощью этого класса абстрактный базовый класс можно создать простым наследованием от [`ABC`](https://python-all.ru/3.5/library/abc.html#abc.ABC), избегая иногда запутанного использования метаклассов.9798Обратите внимание, что тип [`ABC`](https://python-all.ru/3.5/library/abc.html#abc.ABC) по-прежнему [`ABCMeta`](https://python-all.ru/3.5/library/abc.html#abc.ABCMeta), поэтому наследование от [`ABC`](https://python-all.ru/3.5/library/abc.html#abc.ABC) требует обычных мер предосторожности в отношении использования метаклассов, поскольку множественное наследование может привести к конфликтам метаклассов.99100Новое в версии 3.4.101102Модуль [`abc`](https://python-all.ru/3.5/library/abc.html#module-abc) также предоставляет следующие декораторы:103104#### `@abc.abstractmethod`105106Декоратор, указывающий на абстрактные методы.107108Использование этого декоратора требует, чтобы метакласс класса был [`ABCMeta`](https://python-all.ru/3.5/library/abc.html#abc.ABCMeta) или производным от него. Класс, метакласс которого является производным от [`ABCMeta`](https://python-all.ru/3.5/library/abc.html#abc.ABCMeta), не может быть инстанцирован, если все его абстрактные методы и свойства не переопределены. Абстрактные методы можно вызывать с помощью любого из обычных механизмов вызова super. [`abstractmethod()`](https://python-all.ru/3.5/library/abc.html#abc.abstractmethod) может использоваться для объявления абстрактных методов для свойств и дескрипторов.109110Динамическое добавление абстрактных методов в класс или попытка изменить статус абстракции метода или класса после его создания не поддерживаются. [`abstractmethod()`](https://python-all.ru/3.5/library/abc.html#abc.abstractmethod) влияет только на подклассы, полученные с помощью обычного наследования; «виртуальные подклассы», зарегистрированные с помощью метода `register()` ABC, не затрагиваются.111112Когда [`abstractmethod()`](https://python-all.ru/3.5/library/abc.html#abc.abstractmethod) применяется в комбинации с другими дескрипторами методов, он должен применяться как самый внутренний декоратор, как показано в следующих примерах использования:113114```python115class C(metaclass=ABCMeta):116 @abstractmethod117 def my_abstract_method(self, ...):118 ...119 @classmethod120 @abstractmethod121 def my_abstract_classmethod(cls, ...):122 ...123 @staticmethod124 @abstractmethod125 def my_abstract_staticmethod(...):126 ...127128 @property129 @abstractmethod130 def my_abstract_property(self):131 ...132 @my_abstract_property.setter133 @abstractmethod134 def my_abstract_property(self, val):135 ...136137 @abstractmethod138 def _get_x(self):139 ...140 @abstractmethod141 def _set_x(self, val):142 ...143 x = property(_get_x, _set_x)144```145146Для корректного взаимодействия с механизмом абстрактных базовых классов дескриптор должен идентифицировать себя как абстрактный с помощью `__isabstractmethod__`. В общем случае этот атрибут должен быть `True`, если какой-либо из методов, используемых для составления дескриптора, является абстрактным. Например, встроенное свойство Python делает эквивалент следующего:147148```python149class Descriptor:150 ...151 @property152 def __isabstractmethod__(self):153 return any(getattr(f, '__isabstractmethod__', False) for154 f in (self._fget, self._fset, self._fdel))155```156157> **Примечание**158>159> В отличие от абстрактных методов Java, эти абстрактные методы могут иметь реализацию. Эту реализацию можно вызвать через механизм [`super()`](https://python-all.ru/3.5/library/functions.html#super) из класса, который её переопределяет. Это может быть полезно как конечная точка для вызова super в среде, использующей кооперативное множественное наследование.160161#### `@abc.abstractclassmethod`162163Подкласс встроенного [`classmethod()`](https://python-all.ru/3.5/library/functions.html#classmethod), указывающий на абстрактный метод класса. В остальном аналогичен [`abstractmethod()`](https://python-all.ru/3.5/library/abc.html#abc.abstractmethod).164165Этот частный случай устарел, так как декоратор [`classmethod()`](https://python-all.ru/3.5/library/functions.html#classmethod) теперь корректно определяется как абстрактный при применении к абстрактному методу:166167```python168class C(metaclass=ABCMeta):169 @classmethod170 @abstractmethod171 def my_abstract_classmethod(cls, ...):172 ...173```174175Новое в версии 3.2.176177Устарело с версии 3.3: Теперь можно использовать [`classmethod`](https://python-all.ru/3.5/library/functions.html#classmethod) с\\n[`abstractmethod()`](https://python-all.ru/3.5/library/abc.html#abc.abstractmethod), что делает этот декоратор избыточным.178179#### `@abc.abstractstaticmethod`180181Подкласс встроенного [`staticmethod()`](https://python-all.ru/3.5/library/functions.html#staticmethod), указывающий на абстрактный статический метод. В остальном аналогичен [`abstractmethod()`](https://python-all.ru/3.5/library/abc.html#abc.abstractmethod).182183Этот частный случай устарел, так как декоратор [`staticmethod()`](https://python-all.ru/3.5/library/functions.html#staticmethod) теперь корректно определяется как абстрактный при применении к абстрактному методу:184185```python186class C(metaclass=ABCMeta):187 @staticmethod188 @abstractmethod189 def my_abstract_staticmethod(...):190 ...191```192193Новое в версии 3.2.194195Устарело с версии 3.3: Теперь можно использовать [`staticmethod`](https://python-all.ru/3.5/library/functions.html#staticmethod) с\\n[`abstractmethod()`](https://python-all.ru/3.5/library/abc.html#abc.abstractmethod), что делает этот декоратор избыточным.196197#### `@abc.abstractproperty(fget=None, fset=None, fdel=None, doc=None)`198199Подкласс встроенного [`property()`](https://python-all.ru/3.5/library/functions.html#property), указывающий на абстрактное свойство.200201Использование этой функции требует, чтобы метакласс класса был [`ABCMeta`](https://python-all.ru/3.5/library/abc.html#abc.ABCMeta) или был производным от него. Класс, метакласс которого является производным от [`ABCMeta`](https://python-all.ru/3.5/library/abc.html#abc.ABCMeta), не может быть инстанцирован, если все его абстрактные методы и свойства не переопределены. Абстрактные свойства можно вызывать с помощью любого из обычных механизмов вызова «super».202203Этот частный случай устарел, так как декоратор [`property()`](https://python-all.ru/3.5/library/functions.html#property) теперь корректно определяется как абстрактный при применении к абстрактному методу:204205```python206class C(metaclass=ABCMeta):207 @property208 @abstractmethod209 def my_abstract_property(self):210 ...211```212213В приведённом выше примере определяется свойство только для чтения; можно также определить абстрактное свойство для чтения и записи, пометив один или несколько базовых методов как абстрактные.214215```python216class C(metaclass=ABCMeta):217 @property218 def x(self):219 ...220221 @x.setter222 @abstractmethod223 def x(self, val):224 ...225```226227Если абстрактны только некоторые компоненты, то для создания конкретного свойства в подклассе нужно обновить только эти компоненты.228229```python230class D(C):231 @C.x.setter232 def x(self, val):233 ...234```235236Устарело с версии 3.3: Теперь можно использовать [`property`](https://python-all.ru/3.5/library/functions.html#property), `property.getter()`,\\n`property.setter()` и `property.deleter()` с\\n[`abstractmethod()`](https://python-all.ru/3.5/library/abc.html#abc.abstractmethod), что делает этот декоратор избыточным.237238Модуль [`abc`](https://python-all.ru/3.5/library/abc.html#module-abc) также предоставляет следующие функции:239240#### `abc.get_cache_token()`241242Возвращает текущий токен кэша абстрактных базовых классов.243244Токен – это непрозрачный объект (поддерживающий проверку на равенство), идентифицирующий текущую версию кэша абстрактных базовых классов для виртуальных подклассов. Токен изменяется при каждом вызове [`ABCMeta.register()`](https://python-all.ru/3.5/library/abc.html#abc.ABCMeta.register) для любого ABC.245246Новое в версии 3.4.247248Сноски249250| [\[1\]](https://python-all.ru/3.5/library/abc.html#id1) | Программистам на C++ следует отметить, что концепция виртуального базового класса в Python отличается от C++. |251| --- | --- |252