Spec-Zone.ru › Python 3.12

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() влияет только на подклассы, созданные с помощью обычного наследования; это не относится к «виртуальным подклассам», зарегистрированным методом 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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/abc.html

Spec-Zone.ru

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