Документация Python неофициальный перевод

abc.md

281 строк · 20.8 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3/library/abc.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# `abc` – Абстрактные базовые классы89**Исходный код:** [Lib/abc.py](https://python-all.ru/src/3.14/Lib/abc.py)1011---1213Этот модуль предоставляет инфраструктуру для определения [абстрактных базовых классов](https://python-all.ru/3/glossary.html#term-abstract-base-class) (ABC) в Python, как описано в [**PEP 3119**](https://python-all.ru/3/library/abc.html); см. PEP для информации о том, почему это было добавлено в Python. (См. также [**PEP 3141**](https://python-all.ru/3/library/abc.html) и модуль [`numbers`](https://python-all.ru/3/library/numbers.html#module-numbers) относительно иерархии типов для чисел на основе ABC.)1415Модуль [`collections`](https://python-all.ru/3/library/collections.html#module-collections) содержит несколько конкретных классов, которые наследуются от ABC; их, конечно, можно наследовать дальше. Кроме того, подмодуль [`collections.abc`](https://python-all.ru/3/library/collections.abc.html#module-collections.abc) содержит несколько ABC, которые можно использовать для проверки, предоставляет ли класс или экземпляр определённый интерфейс, например, является ли он [хешируемым](https://python-all.ru/3/glossary.html#term-hashable) или является ли он [отображением](https://python-all.ru/3/glossary.html#term-mapping).1617Этот модуль предоставляет метакласс [`ABCMeta`](https://python-all.ru/3/library/abc.html#abc.ABCMeta) для определения ABC и вспомогательный класс [`ABC`](https://python-all.ru/3/library/abc.html#abc.ABC) для альтернативного определения ABC через наследование:1819#### `class abc.ABC`2021Вспомогательный класс, который использует [`ABCMeta`](https://python-all.ru/3/library/abc.html#abc.ABCMeta) в качестве своего метакласса. С помощью этого класса абстрактный базовый класс можно создать, просто унаследовав от `ABC`, что позволяет избежать иногда запутанного использования метаклассов, например:2223```python24from abc import ABC2526class MyABC(ABC):27    pass28```2930Обратите внимание, что типом `ABC` по-прежнему является [`ABCMeta`](https://python-all.ru/3/library/abc.html#abc.ABCMeta), поэтому наследование от `ABC` требует обычных мер предосторожности в отношении использования метаклассов, так как множественное наследование может привести к конфликтам метаклассов. Также можно определить абстрактный базовый класс, передав ключевое слово metaclass и используя напрямую `ABCMeta`, например:3132```python33from abc import ABCMeta3435class MyABC(metaclass=ABCMeta):36    pass37```3839Добавлено в версии 3.4.4041#### `class abc.ABCMeta`4243Метакласс для определения абстрактных базовых классов (ABC).4445Используйте этот метакласс для создания ABC. ABC может быть напрямую унаследован, а затем действует как примесь (mix-in). Также можно регистрировать несвязанные конкретные классы (даже встроенные классы) и несвязанные ABC как «виртуальные подклассы» – они и их потомки будут считаться подклассами регистрирующего ABC встроенной функцией [`issubclass()`](https://python-all.ru/3/library/functions.html#issubclass), но регистрирующий ABC не появится в их MRO (порядке разрешения методов), и реализации методов, определённые регистрирующим ABC, не будут вызываемыми (даже через [`super()`](https://python-all.ru/3/library/functions.html#super)). [\[1\]](https://python-all.ru/3/library/abc.html#id2)4647Классы, созданные с метаклассом `ABCMeta`, имеют следующий метод:4849#### `register(subclass)`5051Регистрирует *подкласс* как «виртуальный подкласс» этого ABC. Например:5253```python54from abc import ABC5556class MyABC(ABC):57    pass5859MyABC.register(tuple)6061assert issubclass(tuple, MyABC)62assert isinstance((), MyABC)63```6465Изменено в версии 3.3: Возвращает зарегистрированный подкласс, что позволяет использовать его в качестве декоратора класса.6667Изменено в версии 3.4: Для обнаружения вызовов `register()` можно использовать функцию [`get_cache_token()`](https://python-all.ru/3/library/abc.html#abc.get_cache_token).6869Также можно переопределить этот метод в абстрактном базовом классе:7071#### `__subclasshook__(subclass)`7273(Должен быть определён как метод класса.)7475Проверяет, считается ли *подкласс* подклассом этого ABC. Это означает, что можно дополнительно настраивать поведение [`issubclass()`](https://python-all.ru/3/library/functions.html#issubclass) без необходимости вызывать [`register()`](https://python-all.ru/3/library/abc.html#abc.ABCMeta.register) для каждого класса, который требуется считать подклассом ABC. (Этот метод класса вызывается из метода [`__subclasscheck__()`](https://python-all.ru/3/reference/datamodel.html#type.__subclasscheck__) ABC.)7677Этот метод должен возвращать `True`, `False` или [`NotImplemented`](https://python-all.ru/3/library/constants.html#NotImplemented). Если он возвращает `True`, то *подкласс* считается подклассом этого ABC. Если он возвращает `False`, то *подкласс* не считается подклассом этого ABC, даже если бы он обычно им был. Если он возвращает `NotImplemented`, проверка на подкласс продолжается обычным механизмом.7879Для демонстрации этих концепций посмотрите на следующий пример определения ABC:8081```python82class Foo:83    def __getitem__(self, index):84        ...85    def __len__(self):86        ...87    def get_iterator(self):88        return iter(self)8990class MyIterable(ABC):9192    @abstractmethod93    def __iter__(self):94        while False:95            yield None9697    def get_iterator(self):98        return self.__iter__()99100    @classmethod101    def __subclasshook__(cls, C):102        if cls is MyIterable:103            if any("__iter__" in B.__dict__ for B in C.__mro__):104                return True105        return NotImplemented106107MyIterable.register(Foo)108```109110ABC `MyIterable` определяет стандартный метод итерируемых объектов, [`__iter__()`](https://python-all.ru/3/reference/datamodel.html#object.__iter__), как абстрактный метод. Приведённую здесь реализацию всё ещё можно вызывать из подклассов. Метод `get_iterator()` также является частью абстрактного базового класса `MyIterable`, но его не обязательно переопределять в неабстрактных производных классах.111112The [`__subclasshook__()`](https://python-all.ru/3/library/abc.html#abc.ABCMeta.__subclasshook__) class method defined here says that any class that has an [`__iter__()`](https://python-all.ru/3/reference/datamodel.html#object.__iter__) method in its [`__dict__`](https://python-all.ru/3/reference/datamodel.html#object.__dict__) (or in that of one of its base classes, accessed via the [`__mro__`](https://python-all.ru/3/reference/datamodel.html#type.__mro__) list) is considered a `MyIterable` too.113114Наконец, последняя строка делает `Foo` виртуальным подклассом `MyIterable`, даже если он не определяет метод [`__iter__()`](https://python-all.ru/3/reference/datamodel.html#object.__iter__) (он использует старый протокол итерирования, определённый через [`__len__()`](https://python-all.ru/3/reference/datamodel.html#object.__len__) и [`__getitem__()`](https://python-all.ru/3/reference/datamodel.html#object.__getitem__)). Обратите внимание, что это не сделает `get_iterator` доступным в качестве метода `Foo`, поэтому он предоставляется отдельно.115116Модуль `abc` также предоставляет следующий декоратор:117118#### `@abc.abstractmethod`119120Декоратор, указывающий на абстрактные методы.121122Использование этого декоратора требует, чтобы метакласс класса был [`ABCMeta`](https://python-all.ru/3/library/abc.html#abc.ABCMeta) или производным от него. Класс, метакласс которого является производным от `ABCMeta`, не может быть инстанцирован, если все его абстрактные методы и свойства не переопределены. Абстрактные методы можно вызывать с помощью любого из обычных механизмов вызова super. `abstractmethod()` может использоваться для объявления абстрактных методов для свойств и дескрипторов.123124Динамическое добавление абстрактных методов в класс или попытка изменить статус абстрактности метода или класса после его создания поддерживаются только с помощью функции [`update_abstractmethods()`](https://python-all.ru/3/library/abc.html#abc.update_abstractmethods). `abstractmethod()` влияет только на подклассы, полученные с помощью обычного наследования; «виртуальные подклассы», зарегистрированные методом [`register()`](https://python-all.ru/3/library/abc.html#abc.ABCMeta.register) ABC, не затрагиваются.125126Когда `abstractmethod()` применяется в комбинации с другими дескрипторами методов, он должен применяться как самый внутренний декоратор, как показано в следующих примерах использования:127128```python129class C(ABC):130    @abstractmethod131    def my_abstract_method(self, arg1):132        ...133    @classmethod134    @abstractmethod135    def my_abstract_classmethod(cls, arg2):136        ...137    @staticmethod138    @abstractmethod139    def my_abstract_staticmethod(arg3):140        ...141142    @property143    @abstractmethod144    def my_abstract_property(self):145        ...146    @my_abstract_property.setter147    @abstractmethod148    def my_abstract_property(self, val):149        ...150151    @abstractmethod152    def _get_x(self):153        ...154    @abstractmethod155    def _set_x(self, val):156        ...157    x = property(_get_x, _set_x)158```159160Для корректной работы с механизмом абстрактных базовых классов дескриптор должен идентифицировать себя как абстрактный с помощью `__isabstractmethod__`. В общем случае этот атрибут должен быть `True`, если хотя бы один из методов, используемых для составления дескриптора, является абстрактным. Например, встроенный [`property`](https://python-all.ru/3/library/functions.html#property) языка Python делает следующее:161162```python163class Descriptor:164    ...165    @property166    def __isabstractmethod__(self):167        return any(getattr(f, '__isabstractmethod__', False) for168                   f in (self._fget, self._fset, self._fdel))169```170171> **Примечание**172>173> В отличие от абстрактных методов Java, эти абстрактные методы могут иметь реализацию. Эту реализацию можно вызвать через механизм [`super()`](https://python-all.ru/3/library/functions.html#super) из класса, который её переопределяет. Это может быть полезно как конечная точка для вызова super в среде, использующей кооперативное множественное наследование.174175Модуль `abc` также поддерживает следующие устаревшие декораторы:176177#### `@abc.abstractclassmethod`178179Добавлено в версии 3.2.180181Устарело с версии 3.3: Теперь можно использовать [`classmethod`](https://python-all.ru/3/library/functions.html#classmethod) с\\n[`abstractmethod()`](https://python-all.ru/3/library/abc.html#abc.abstractmethod), что делает этот декоратор избыточным.182183Подкласс встроенного [`classmethod()`](https://python-all.ru/3/library/functions.html#classmethod), указывающий на абстрактный метод класса. В остальном аналогичен [`abstractmethod()`](https://python-all.ru/3/library/abc.html#abc.abstractmethod).184185Этот частный случай устарел, так как декоратор [`classmethod()`](https://python-all.ru/3/library/functions.html#classmethod) теперь корректно определяется как абстрактный при применении к абстрактному методу:186187```python188class C(ABC):189    @classmethod190    @abstractmethod191    def my_abstract_classmethod(cls, arg):192        ...193```194195#### `@abc.abstractstaticmethod`196197Добавлено в версии 3.2.198199Устарело с версии 3.3: Теперь можно использовать [`staticmethod`](https://python-all.ru/3/library/functions.html#staticmethod) с\\n[`abstractmethod()`](https://python-all.ru/3/library/abc.html#abc.abstractmethod), что делает этот декоратор избыточным.200201Подкласс встроенного [`staticmethod()`](https://python-all.ru/3/library/functions.html#staticmethod), указывающий на абстрактный статический метод. В остальном аналогичен [`abstractmethod()`](https://python-all.ru/3/library/abc.html#abc.abstractmethod).202203Этот частный случай устарел, так как декоратор [`staticmethod()`](https://python-all.ru/3/library/functions.html#staticmethod) теперь корректно определяется как абстрактный при применении к абстрактному методу:204205```python206class C(ABC):207    @staticmethod208    @abstractmethod209    def my_abstract_staticmethod(arg):210        ...211```212213#### `@abc.abstractproperty`214215Устарело с версии 3.3: Теперь можно использовать [`property`](https://python-all.ru/3/library/functions.html#property), [`property.getter()`](https://python-all.ru/3/library/functions.html#property.getter),\\n[`property.setter()`](https://python-all.ru/3/library/functions.html#property.setter) и [`property.deleter()`](https://python-all.ru/3/library/functions.html#property.deleter) с\\n[`abstractmethod()`](https://python-all.ru/3/library/abc.html#abc.abstractmethod), что делает этот декоратор избыточным.216217Подкласс встроенного [`property()`](https://python-all.ru/3/library/functions.html#property), указывающий на абстрактное свойство.218219Этот частный случай устарел, так как декоратор [`property()`](https://python-all.ru/3/library/functions.html#property) теперь корректно определяется как абстрактный при применении к абстрактному методу:220221```python222class C(ABC):223    @property224    @abstractmethod225    def my_abstract_property(self):226        ...227```228229В приведённом выше примере определяется свойство только для чтения; можно также определить абстрактное свойство для чтения и записи, пометив один или несколько базовых методов как абстрактные.230231```python232class C(ABC):233    @property234    def x(self):235        ...236237    @x.setter238    @abstractmethod239    def x(self, val):240        ...241```242243Если абстрактны только некоторые компоненты, то для создания конкретного свойства в подклассе нужно обновить только эти компоненты.244245```python246class D(C):247    @C.x.setter248    def x(self, val):249        ...250```251252Модуль `abc` также предоставляет следующие функции:253254#### `abc.get_cache_token()`255256Возвращает текущий токен кэша абстрактных базовых классов.257258Токен – это непрозрачный объект (поддерживающий проверку на равенство), идентифицирующий текущую версию кэша абстрактных базовых классов для виртуальных подклассов. Токен изменяется при каждом вызове [`ABCMeta.register()`](https://python-all.ru/3/library/abc.html#abc.ABCMeta.register) для любого ABC.259260Добавлено в версии 3.4.261262#### `abc.update_abstractmethods(cls)`263264Функция для пересчёта статуса абстракции абстрактного класса. Эта функция должна вызываться, если абстрактные методы класса были реализованы или изменены после его создания. Обычно эта функция должна вызываться внутри декоратора класса.265266Возвращает *cls*, чтобы обеспечить использование в качестве декоратора класса.267268Если *cls* не является экземпляром [`ABCMeta`](https://python-all.ru/3/library/abc.html#abc.ABCMeta), ничего не делает.269270> **Примечание**271>272> Эта функция предполагает, что суперклассы *cls* уже обновлены. Она не обновляет никакие подклассы.273274Добавлено в версии 3.10.275276Сноски277278\[[1](https://python-all.ru/3/library/abc.html#id1)\]279280Программистам на C++ следует отметить, что концепция виртуального базового класса в Python отличается от C++.281