abc — Абстрактные базовые классы
Исходный код: Lib/abc.py
Этот модуль предоставляет инфраструктуру для определения абстрактных базовых классов (ABC) в Python, как описано в PEP 3119; в PEP объясняется, почему эта возможность была добавлена в Python. (См. также PEP 3141 и модуль numbers, посвящённый иерархии типов чисел на основе ABC.)
В модуле collections есть несколько конкретных классов, производных от ABC; их, конечно, можно наследовать и дальше. Кроме того, подмодуль collections.abc содержит ABC, которые можно использовать, чтобы проверить, предоставляет ли класс или экземпляр определённый интерфейс, например, является ли он хешируемым или отображением.
Этот модуль предоставляет метакласс ABCMeta для определения ABC и вспомогательный класс ABC, позволяющий определять ABC через наследование:
-
class abc.ABC -
Вспомогательный класс, метаклассом которого является
ABCMeta. С помощью этого класса абстрактный базовый класс можно создать, просто унаследовавшись отABC, избегая порой запутанного использования метаклассов. Например:from abc import ABC class MyABC(ABC): passОбратите внимание, что тип
ABCпо-прежнему являетсяABCMeta, поэтому при наследовании отABCнеобходимо соблюдать обычные меры предосторожности при использовании метаклассов, поскольку множественное наследование может привести к конфликтам метаклассов. Абстрактный базовый класс также можно определить, передав аргумент metaclass и используя непосредственноABCMeta. Например:from abc import ABCMeta class MyABC(metaclass=ABCMeta): passДобавлено в версии 3.4.
-
class abc.ABCMeta -
Метакласс для определения абстрактных базовых классов (ABC).
Используйте этот метакласс для создания ABC. От ABC можно напрямую наследоваться, после чего она будет выступать в роли класса-миксина. Также можно зарегистрировать не связанные с ней конкретные классы (даже встроенные классы) и другие ABC как «виртуальные подклассы» — они и их потомки будут считаться подклассами зарегистрировавшей их ABC встроенной функцией
issubclass(), однако зарегистрировавшая их ABC не появится в их MRO (порядке разрешения методов), а реализации методов, определённые в зарегистрировавшей их ABC, нельзя будет вызвать (даже черезsuper()). [1]Классы, созданные с метаклассом
ABCMeta, имеют следующий метод:-
register(subclass) -
Зарегистрировать подкласс как «виртуальный подкласс» этой ABC. Например:
from abc import ABC class MyABC(ABC): pass MyABC.register(tuple) assert issubclass(tuple, MyABC) assert isinstance((), MyABC)Изменено в версии 3.3: Возвращает зарегистрированный подкласс, что позволяет использовать метод как декоратор класса.
Изменено в версии 3.4: Для обнаружения вызовов
register()можно использовать функциюget_cache_token().
Этот метод также можно переопределить в абстрактном базовом классе:
-
__subclasshook__(subclass) -
(Должен быть определён как метод класса.)
Проверить, считается ли подкласс подклассом этой ABC. Это позволяет дополнительно настроить поведение
issubclass(), не вызываяregister()для каждого класса, который требуется считать подклассом этой ABC. (Этот метод класса вызывается методом__subclasscheck__()ABC.)Этот метод должен возвращать
True,FalseилиNotImplemented. Если он возвращаетTrue, подкласс считается подклассом этой ABC. Если он возвращаетFalse, подкласс не считается подклассом этой ABC, даже если обычно считался бы. Если он возвращаетNotImplemented, проверка подкласса продолжается обычным способом.
Чтобы увидеть эти концепции в действии, рассмотрите следующий пример определения ABC:
class Foo: def __getitem__(self, index): ... def __len__(self): ... def get_iterator(self): return iter(self) class MyIterable(ABC): @abstractmethod def __iter__(self): while False: yield None def get_iterator(self): return self.__iter__() @classmethod def __subclasshook__(cls, C): if cls is MyIterable: if any("__iter__" in B.__dict__ for B in C.__mro__): return True return NotImplemented MyIterable.register(Foo)ABC
MyIterableопределяет стандартный метод итерации__iter__()как абстрактный метод. Реализацию, приведённую здесь, по-прежнему можно вызывать из подклассов. Методget_iterator()также входит в абстрактный базовый классMyIterable, но в производных классах, не являющихся абстрактными, его переопределять необязательно.Определённый здесь метод класса
__subclasshook__()указывает, что любой класс, у которого есть метод__iter__()в его__dict__(или в атрибуте одного из его базовых классов, доступном через список__mro__), также считаетсяMyIterable.Наконец, последняя строка делает
Fooвиртуальным подклассомMyIterable, хотя в нём не определён метод__iter__()(вместо этого используется старый протокол итерируемых объектов, определённый через__len__()и__getitem__()). Обратите внимание, что это не сделаетget_iteratorдоступным как методFoo, поэтому он предоставляется отдельно. -
Модуль abc также предоставляет следующий декоратор:
-
@abc.abstractmethod -
Декоратор, указывающий на абстрактные методы.
Для использования этого декоратора метаклассом класса должен быть
ABCMetaили производный от него метакласс. Нельзя создать экземпляр класса с метаклассом, производным отABCMeta, пока не переопределены все его абстрактные методы и свойства. Абстрактные методы можно вызывать с помощью любого из обычных механизмов вызова «super».abstractmethod()можно использовать для объявления абстрактных методов свойств и дескрипторов.Динамическое добавление абстрактных методов в класс или попытки изменить абстрактный статус метода или класса после его создания поддерживаются только с помощью функции
update_abstractmethods(). Декораторabstractmethod()влияет только на подклассы, созданные посредством обычного наследования; он не влияет на «виртуальные подклассы», зарегистрированные методомregister()ABC.Если
abstractmethod()используется вместе с другими дескрипторами методов, его следует применять как самый внутренний декоратор, как показано в примерах ниже:class C(ABC): @abstractmethod def my_abstract_method(self, arg1): ... @classmethod @abstractmethod def my_abstract_classmethod(cls, arg2): ... @staticmethod @abstractmethod def my_abstract_staticmethod(arg3): ... @property @abstractmethod def my_abstract_property(self): ... @my_abstract_property.setter @abstractmethod def my_abstract_property(self, val): ... @abstractmethod def _get_x(self): ... @abstractmethod def _set_x(self, val): ... x = property(_get_x, _set_x)Для корректного взаимодействия с механизмом абстрактных базовых классов дескриптор должен обозначать себя как абстрактный с помощью
__isabstractmethod__. В общем случае этот атрибут должен иметь значениеTrue, если абстрактен хотя бы один из методов, используемых для составления дескриптора. Например, встроенный тип Pythonpropertyвыполняет эквивалент следующих действий:class Descriptor: ... @property def __isabstractmethod__(self): return any(getattr(f, '__isabstractmethod__', False) for f in (self._fget, self._fset, self._fdel))Примечание
В отличие от абстрактных методов Java, эти абстрактные методы могут иметь реализацию. Эту реализацию можно вызвать из класса, который переопределяет метод, с помощью механизма
super(). Это может быть полезно в качестве конечной точки для вызова super в платформе, использующей кооперативное множественное наследование.
Модуль abc также поддерживает следующие устаревшие декораторы:
-
@abc.abstractclassmethod -
Добавлено в версии 3.2.
Устарело с версии 3.3: Теперь
classmethodможно использовать сabstractmethod(), поэтому этот декоратор стал избыточным.Подкласс встроенного
classmethod(), указывающий на абстрактный метод класса. В остальном он аналогиченabstractmethod().Этот особый случай устарел, поскольку декоратор
classmethod()теперь корректно распознаётся как абстрактный при применении к абстрактному методу:class C(ABC): @classmethod @abstractmethod def my_abstract_classmethod(cls, arg): ...
-
@abc.abstractstaticmethod -
Добавлено в версии 3.2.
Устарело с версии 3.3: Теперь
staticmethodможно использовать сabstractmethod(), поэтому этот декоратор стал избыточным.Подкласс встроенного
staticmethod(), указывающий на абстрактный статический метод. В остальном он аналогиченabstractmethod().Этот особый случай устарел, поскольку декоратор
staticmethod()теперь корректно распознаётся как абстрактный при применении к абстрактному методу:class C(ABC): @staticmethod @abstractmethod def my_abstract_staticmethod(arg): ...
-
@abc.abstractproperty -
Устарело с версии 3.3: Теперь
property,property.getter(),property.setter()иproperty.deleter()можно использовать сabstractmethod(), поэтому этот декоратор стал избыточным.Подкласс встроенного
property(), указывающий на абстрактное свойство.Этот особый случай устарел, поскольку декоратор
property()теперь корректно распознаётся как абстрактный при применении к абстрактному методу:class C(ABC): @property @abstractmethod def my_abstract_property(self): ...В приведённом выше примере определяется свойство только для чтения; также можно определить абстрактное свойство для чтения и записи, пометив один или несколько нижележащих методов как абстрактные:
class C(ABC): @property def x(self): ... @x.setter @abstractmethod def x(self, val): ...Если абстрактны только некоторые компоненты, для создания конкретного свойства в подклассе достаточно обновить только эти компоненты:
class D(C): @C.x.setter def x(self, val): ...
Модуль abc также предоставляет следующие функции:
-
abc.get_cache_token() -
Возвращает текущий токен кэша абстрактных базовых классов.
Токен — это непрозрачный объект (поддерживающий проверку на равенство), который идентифицирует текущую версию кэша абстрактных базовых классов для виртуальных подклассов. Токен изменяется при каждом вызове
ABCMeta.register()для любой ABC.Добавлено в версии 3.4.
-
abc.update_abstractmethods(cls) -
Функция для повторного вычисления абстрактного статуса класса. Эту функцию следует вызывать, если абстрактные методы класса были реализованы или изменены после его создания. Обычно эту функцию следует вызывать из декоратора класса.
Возвращает cls, что позволяет использовать функцию как декоратор класса.
Если cls не является экземпляром
ABCMeta, функция ничего не делает.Примечание
Эта функция предполагает, что суперклассы cls уже обновлены. Она не обновляет подклассы.
Добавлено в версии 3.10.
Сноски
© 2001–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/abc.html