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 не будет отображаться в их порядке разрешения методов (Method Resolution Order, 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()может использоваться для объявления абстрактных методов для свойств и дескрипторов.Динамическое добавление абстрактных методов к классу или попытка изменить статус абстракции метода или класса после его создания не поддерживаются.
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()в классе, который её переопределяет. Это может быть полезно как конечная точка для вызова 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.
Примечания
-
1 -
Программисты C++ должны отметить, что концепция виртуального базового класса в Python не такая же, как в C++.
© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.9/library/abc.html