28.8. abc – Абстрактные базовые классы¶abc – Abstract Base Classes
Новое в версии 2.6.
Исходный код: Lib/abc.py
Этот модуль предоставляет инфраструктуру для определения абстрактных базовых
классов (ABC) в Python, как описано в PEP 3119; см. PEP, чтобы узнать, почему это было добавлено в Python. (См. также PEP 3141 и модуль numbers, касающийся иерархии типов для чисел на основе ABC.)
Модуль collections содержит несколько конкретных классов, которые наследуются от ABC; их, конечно, можно наследовать дальше. Кроме того, модуль collections содержит несколько ABC, которые можно использовать для проверки того, предоставляет ли класс или экземпляр определённый интерфейс, например, является ли он хешируемым или отображением.
Этот модуль предоставляет следующий класс:
-
class
abc.ABCMeta¶ Метакласс для определения абстрактных базовых классов (ABC).
Используйте этот метакласс для создания ABC. ABC может быть напрямую унаследован, а затем действует как примесь (mix-in). Также можно регистрировать несвязанные конкретные классы (даже встроенные классы) и несвязанные ABC как «виртуальные подклассы» – они и их потомки будут считаться подклассами регистрирующего ABC встроенной функцией
issubclass(), но регистрирующий ABC не появится в их MRO (порядке разрешения методов), и реализации методов, определённые регистрирующим ABC, не будут вызываемыми (даже черезsuper()). 1Классы, созданные с метаклассом
ABCMeta, имеют следующий метод:-
register(subclass)¶ Регистрирует подкласс как «виртуальный подкласс» этого ABC. Например:
from abc import ABCMeta class MyABC: __metaclass__ = ABCMeta MyABC.register(tuple) assert issubclass(tuple, MyABC) assert isinstance((), MyABC)
Также можно переопределить этот метод в абстрактном базовом классе:
-
__subclasshook__(subclass)¶ (Должен быть определён как метод класса.)
Проверяет, считается ли подкласс подклассом этого ABC. Это означает, что можно дополнительно настраивать поведение
issubclassбез необходимости вызыватьregister()для каждого класса, который требуется считать подклассом ABC. (Этот метод класса вызывается из метода__subclasscheck__()ABC.)Этот метод должен возвращать
True,FalseилиNotImplemented. Если он возвращаетTrue, то подкласс считается подклассом этого ABC. Если он возвращаетFalse, то подкласс не считается подклассом этого ABC, даже если бы он обычно им был. Если он возвращаетNotImplemented, проверка на подкласс продолжается обычным механизмом.
Для демонстрации этих концепций посмотрите на следующий пример определения ABC:
class Foo(object): def __getitem__(self, index): ... def __len__(self): ... def get_iterator(self): return iter(self) class MyIterable: __metaclass__ = ABCMeta @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, но его не обязательно переопределять в неабстрактных производных классах.The
__subclasshook__()class method defined here says that any class that has an__iter__()method in its__dict__(or in that of one of its base classes, accessed via the__mro__list) is considered aMyIterabletoo.Наконец, последняя строка делает
Fooвиртуальным подклассомMyIterable, даже если он не определяет метод__iter__()(он использует старый протокол итерирования, определённый через__len__()и__getitem__()). Обратите внимание, что это не сделаетget_iteratorдоступным в качестве методаFoo, поэтому он предоставляется отдельно.-
Он также предоставляет следующие декораторы:
-
abc.abstractmethod(function)¶ Декоратор, указывающий на абстрактные методы.
Использование этого декоратора требует, чтобы метакласс класса был
ABCMetaили был производным от него. Класс, метакласс которого является производным отABCMeta, не может быть инстанциирован, пока все его абстрактные методы и свойства не будут переопределены. Абстрактные методы можно вызывать с помощью любого из обычных механизмов вызова ‘super’.Динамическое добавление абстрактных методов в класс или попытка изменить статус абстракции метода или класса после его создания не поддерживаются.
abstractmethod()влияет только на подклассы, полученные с помощью обычного наследования; «виртуальные подклассы», зарегистрированные с помощью методаregister()ABC, не затрагиваются.Использование:
class C: __metaclass__ = ABCMeta @abstractmethod def my_abstract_method(self, ...): ...
Примечание
В отличие от абстрактных методов Java, эти абстрактные методы могут иметь реализацию. Эту реализацию можно вызвать через механизм
super()из класса, который её переопределяет. Это может быть полезно как конечная точка для вызова super в среде, использующей кооперативное множественное наследование.
-
abc.abstractproperty([fget[, fset[, fdel[, doc]]]])¶ Подкласс встроенного
property(), указывающий на абстрактное свойство.Использование этой функции требует, чтобы метакласс класса был
ABCMetaили был производным от него. Класс, метакласс которого является производным отABCMeta, не может быть инстанциирован, пока все его абстрактные методы и свойства не будут переопределены. Абстрактные свойства можно вызывать с помощью любого из обычных механизмов вызова ‘super’.Использование:
class C: __metaclass__ = ABCMeta @abstractproperty def my_abstract_property(self): ...
Это определяет свойство только для чтения; можно также определить абстрактное свойство чтения-записи, используя «длинную» форму объявления свойства:
class C: __metaclass__ = ABCMeta def getx(self): ... def setx(self, value): ... x = abstractproperty(getx, setx)
Сноски
- 1
Программистам на C++ следует отметить, что концепция виртуального базового класса в Python отличается от C++.