Spec-Zone.ru › Python 3.11

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() влияет только на подклассы, полученные с помощью обычного наследования; «виртуальные подклассы», зарегистрированные с помощью метода ABC register(), не затрагиваются.

Когда 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.11/library/abc.html

Spec-Zone.ru

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