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, если какой-либо из методов, использованных для создания дескриптора, является абстрактным. Например, встроенная функция Python@propertyделает эквивалент следующего: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 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/abc.html