abc
— Абстрактные базовые классы¶
Исходный код: Lib/abc.py.
Этот модуль предоставляет инфраструктуру для определения abstract base classes (ABCs) в Python, как описано в PEP 3119; см. PEP о том, почему это было добавлено в Python. (См. также PEP 3141 и модуль numbers
относительно иерархии типов для чисел на основе ABCs).
В модуле collections
есть несколько конкретных классов, которые происходят от ABCs; они, конечно, могут быть продолжены. Кроме того, в подмодуле 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 (Method Resolution Order) и реализации методов, определенные регистрирующим ABC, не будут вызываться (даже черезsuper()
). 1Классы, созданные с метаклассом
ABCMeta
, имеют следующий метод:-
register
(subclass)¶ Зарегистрируйте 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__()
АВС).Этот метод должен возвращать
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
определяет стандартный метод iterable,__iter__()
, как абстрактный метод. Приведенная здесь реализация все еще может быть вызвана из подклассов. Методget_iterator()
также является частью абстрактного базового классаMyIterable
, но его не нужно переопределять в неабстрактных производных классах.Определенный здесь метод класса
__subclasshook__()
говорит, что любой класс, имеющий метод__iter__()
в своем__dict__
(или в методе одного из своих базовых классов, доступ к которому осуществляется через список__mro__
), тоже считаетсяMyIterable
.Наконец, последняя строка делает
Foo
виртуальным подклассомMyIterable
, даже если он не определяет метод__iter__()
(он использует протокол итерабельности старого стиля, определенный в терминах__len__()
и__getitem__()
). Обратите внимание, что это не сделаетget_iterator
доступным как методFoo
, поэтому он предоставляется отдельно.-
Модуль abc
также предоставляет следующий декоратор:
-
@
abc.
abstractmethod
¶ Декоратор, указывающий на абстрактные методы.
Использование этого декоратора требует, чтобы метакласс класса был
ABCMeta
или был производным от него. Класс, имеющий метакласс, производный отABCMeta
, не может быть инстанцирован, пока не будут переопределены все его абстрактные методы и свойства. Абстрактные методы могут быть вызваны с помощью любого из обычных механизмов вызова «супер».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
, если любой из методов, используемых для составления дескриптора, является абстрактным. Например, встроенная в 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()
из класса, который ее переопределяет. Это может быть полезно в качестве конечной точки для супервызова во фреймворке, использующем кооперативное множественное наследование.
Модуль 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.
Сноски
- 1
Программисты C++ должны заметить, что концепция виртуального базового класса в Python не такая же, как в C++.