Spec-Zone.ru › Python 3.5

abc — Абстрактные базовые классы

Исходный код: Lib/abc.py

Этот модуль предоставляет инфраструктуру для определения абстрактных базовых классов (ABC) в Python, как описано в PEP 3119; см. PEP для объяснения добавления этого в Python. (См. также PEP 3141 и numbers модуль, касающийся иерархии типов чисел на основе ABC.)

Модуль collections содержит некоторые конкретные классы, которые наследуются от ABC; их, конечно, можно далее расширять. Кроме того, подмодуль collections.abc содержит некоторые ABC, которые могут использоваться для проверки, предоставляет ли класс или экземпляр определённый интерфейс, например, является ли он хешируемым или отображением.

Этот модуль предоставляет следующие классы:

class abc.ABCMeta

Метакласс для определения абстрактных базовых классов (ABC).

Используйте этот метакласс для создания ABC. ABC может быть унаследован непосредственно и затем выступать как класс-миксин. Вы также можете регистрировать несвязанные конкретные классы (даже встроенные классы) и несвязанные ABC в качестве «виртуальных подклассов» — эти и их потомки будут считаться подклассами регистрирующего ABC функцией issubclass(), но регистрирующий ABC не будет отображаться в их порядке разрешения методов (Method Resolution Order) ни методы, определённые регистрирующим ABC, не будут вызываемыми (даже не через super()). [1]

Классы, созданные с метаклассом ABCMeta, имеют следующий метод:

register(subclass)

Регистрирует подкласс как «виртуальный подкласс» этого ABC. Например:

from abc import ABCMeta

class MyABC(metaclass=ABCMeta):
    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(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, но он не обязательно должен быть переопределён в неабстрактных производных классах.

Метод класса __subclasshook__(), определённый здесь, говорит, что любой класс, имеющий метод __iter__() в своём __dict__ (или в одном из его базовых классов, доступных через список __mro__), также считается MyIterable.

Наконец, последняя строка делает Foo виртуальным подклассом MyIterable, даже если он не определяет метод __iter__() (он использует протокол итерируемых старого стиля, определённый в терминах __len__() и __getitem__()). Обратите внимание, что это не сделает get_iterator доступным как метод Foo, поэтому он предоставляется отдельно.

class abc.ABC

Вспомогательный класс, имеющий ABCMeta в качестве метакласса. С помощью этого класса абстрактный базовый класс можно создать, просто унаследовав от ABC, избегая иногда запутанного использования метаклассов.

Обратите внимание, что тип ABC всё ещё ABCMeta, поэтому наследование от ABC требует обычных предосторожностей в отношении использования метаклассов, так как множественное наследование может привести к конфликтам метаклассов.

Добавлено в версии 3.4.

Модуль abc также предоставляет следующие декораторы:

@abc.abstractmethod

Декоратор, указывающий абстрактные методы.

Использование этого декоратора требует, чтобы метакласс класса был ABCMeta или был от него унаследован. Класс, имеющий метакласс, унаследованный от ABCMeta, не может быть инстанцирован, если все его абстрактные методы и свойства не переопределены. Абстрактные методы можно вызывать с помощью любых обычных механизмов вызова «super». abstractmethod() можно использовать для объявления абстрактных методов для свойств и дескрипторов.

Динамическое добавление абстрактных методов в класс или попытка изменить статус абстракции метода или класса после его создания не поддерживаются. abstractmethod() влияет только на подклассы, полученные с помощью обычного наследования; «виртуальные подклассы», зарегистрированные с помощью метода register() ABC, не затрагиваются.

Когда abstractmethod() применяется в сочетании с другими дескрипторами методов, он должен применяться как самый внутренний декоратор, как показано в следующих примерах использования:

class C(metaclass=ABCMeta):
    @abstractmethod
    def my_abstract_method(self, ...):
        ...
    @classmethod
    @abstractmethod
    def my_abstract_classmethod(cls, ...):
        ...
    @staticmethod
    @abstractmethod
    def my_abstract_staticmethod(...):
        ...

    @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.abstractclassmethod

Подкласс встроенного classmethod(), указывающий абстрактный метод класса. В остальном он подобен abstractmethod().

Этот специальный случай устарел, так как декоратор classmethod() теперь правильно идентифицируется как абстрактный, когда применяется к абстрактному методу:

class C(metaclass=ABCMeta):
    @classmethod
    @abstractmethod
    def my_abstract_classmethod(cls, ...):
        ...

Добавлено в версии 3.2.

Устаревшее начиная с версии 3.3: Теперь можно использовать classmethod с abstractmethod(), что делает этот декоратор излишним.

@abc.abstractstaticmethod

Подкласс встроенной функции staticmethod(), указывающий на абстрактный статический метод. В остальном он похож на abstractmethod().

Этот специальный случай устарел, так как декоратор staticmethod() теперь правильно идентифицируется как абстрактный, когда применяется к абстрактному методу:

class C(metaclass=ABCMeta):
    @staticmethod
    @abstractmethod
    def my_abstract_staticmethod(...):
        ...

Добавлен в версии 3.2.

Устарело начиная с версии 3.3: Теперь можно использовать декоратор staticmethod с abstractmethod(), что делает этот декоратор избыточным.

@abc.abstractproperty(fget=None, fset=None, fdel=None, doc=None)

Подкласс встроенного property(), указывающий на абстрактное свойство.

Использование этой функции требует, чтобы метакласс класса был ABCMeta или был от него производным. Класс, метакласс которого получен от ABCMeta, не может быть инстанцирован, пока не переопределены все его абстрактные методы и свойства. К абстрактным свойствам можно обращаться с помощью любых обычных механизмов вызова «super».

Этот специальный случай устарел, так как декоратор property() теперь правильно идентифицируется как абстрактный, когда применяется к абстрактному методу:

class C(metaclass=ABCMeta):
    @property
    @abstractmethod
    def my_abstract_property(self):
        ...

В приведенном выше примере определено только для чтения свойство; вы также можете определить абстрактное свойство для чтения и записи, соответствующим образом отметив один или несколько из основных методов как абстрактные:

class C(metaclass=ABCMeta):
    @property
    def x(self):
        ...

    @x.setter
    @abstractmethod
    def x(self, val):
        ...

Если только некоторые компоненты являются абстрактными, необходимо обновить только эти компоненты, чтобы создать конкретное свойство в подклассе:

class D(C):
    @C.x.setter
    def x(self, val):
        ...

Устарело начиная с версии 3.3: Теперь можно использовать property, property.getter(), property.setter() и property.deleter() с abstractmethod(), что делает этот декоратор избыточным.

Модуль abc также предоставляет следующие функции:

abc.get_cache_token()

Возвращает текущий токен кэша абстрактных базовых классов.

Токен — это непрозрачный объект (поддерживающий проверку на равенство), определяющий текущую версию кэша абстрактных базовых классов для виртуальных подклассов. Токен изменяется при каждом вызове ABCMeta.register() для любого ABC.

Добавлен в версии 3.4.

Примечания

[1] Разработчики C++ должны учитывать, что концепция виртуальных базовых классов в Python не совпадает с концепцией виртуальных базовых классов в C++

© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.5/library/abc.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API