abc
— Абстрактные базовые классы¶
Исходный код: Lib/abc.py
Этот модуль предоставляет инфраструктуру для определения abstract base classes (азбуки) в Python, как описано в PEP 3119; смотрите PEP, чтобы узнать, почему это было добавлено в Python. (Смотрите также PEP 3141 и модуль numbers
, посвященный иерархии типов чисел на основе азбуки.)
В модуле collections
есть несколько конкретных классов, которые являются производными от ABC; они, конечно, могут быть получены в дальнейшем. Кроме того, подмодуль collections.abc
содержит некоторые азбуки, которые можно использовать для проверки того, предоставляет ли класс или экземпляр определенный интерфейс, например, если это hashable или если это mapping.
Этот модуль предоставляет метакласс ABCMeta
для определения азбуки и вспомогательный класс 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)¶
(Должен быть определен как метод класса.)
Проверьте, считается ли 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()
влияет только на подклассы, полученные с использованием обычного наследования; «виртуальные подклассы», зарегистрированные с помощью метода ABCregister()
, не затрагиваются.Когда
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()
из класса, который ее переопределяет. Это может быть полезно в качестве конечной точки для супер-вызова во фреймворке, использующем совместное множественное наследование.
Модуль 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.
Сноски