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