abc – Абстрактные базовые классы¶abc – Abstract Base Classes
Исходный код: 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 может быть напрямую унаследован, а затем действует как примесь (mix-in). Также можно регистрировать несвязанные конкретные классы (даже встроенные классы) и несвязанные 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, но его не обязательно переопределять в неабстрактных производных классах.The
__subclasshook__()class method defined here says that any class that has an__iter__()method in its__dict__(or in that of one of its base classes, accessed via the__mro__list) is considered aMyIterabletoo.Наконец, последняя строка делает
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, если хотя бы один из методов, используемых для составления дескриптора, является абстрактным. Например, встроенныйpropertyязыка Python делает следующее: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с\nabstractmethod(), что делает этот декоратор избыточным.Подкласс встроенного
classmethod(), указывающий на абстрактный метод класса. В остальном аналогиченabstractmethod().Этот частный случай устарел, так как декоратор
classmethod()теперь корректно определяется как абстрактный при применении к абстрактному методу:class C(ABC): @classmethod @abstractmethod def my_abstract_classmethod(cls, arg): ...
- @abc.abstractstaticmethod¶
Добавлено в версии 3.2.
Устарело с версии 3.3: Теперь можно использовать
staticmethodс\nabstractmethod(), что делает этот декоратор избыточным.Подкласс встроенного
staticmethod(), указывающий на абстрактный статический метод. В остальном аналогиченabstractmethod().Этот частный случай устарел, так как декоратор
staticmethod()теперь корректно определяется как абстрактный при применении к абстрактному методу:class C(ABC): @staticmethod @abstractmethod def my_abstract_staticmethod(arg): ...
- @abc.abstractproperty¶
Устарело с версии 3.3: Теперь можно использовать
property,property.getter(),\nproperty.setter()иproperty.deleter()с\nabstractmethod(), что делает этот декоратор избыточным.Подкласс встроенного
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.
Сноски
Эта страница – перевод. Оригинал на английском – docs.python.org. Нашли неточность? Сообщите нам.