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

abc.md

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

1> **Источник:** https://python-all.ru/3.3/library/abc.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 28.7. [`abc`](https://python-all.ru/3.3/library/abc.html#module-abc) – Абстрактные базовые классы89**Исходный код:** [Lib/abc.py](https://python-all.ru/src/3.3/Lib/abc.py)1011---1213Этот модуль предоставляет инфраструктуру для определения [*абстрактных базовых классов*](https://python-all.ru/3.3/glossary.html#term-abstract-base-class) (ABC) в Python, как описано в [**PEP 3119**](https://python-all.ru/3.3/library/abc.html); см. PEP, чтобы понять, почему это было добавлено в Python. (См. также [**PEP 3141**](https://python-all.ru/3.3/library/abc.html) и модуль [`numbers`](https://python-all.ru/3.3/library/numbers.html#module-numbers) относительно иерархии типов для чисел на основе ABC.)1415Модуль [`collections`](https://python-all.ru/3.3/library/collections.html#module-collections) содержит несколько конкретных классов, производных от ABC; их, конечно, можно наследовать далее. Кроме того, подмодуль [`collections.abc`](https://python-all.ru/3.3/library/collections.abc.html#module-collections.abc) содержит ABC, которые можно использовать для проверки, предоставляет ли класс или экземпляр определённый интерфейс, например, является ли он хешируемым или отображением.1617Этот модуль предоставляет следующий класс:1819#### `class abc.ABCMeta`2021Метакласс для определения абстрактных базовых классов (ABC).2223Use this metaclass to create an ABC. An ABC can be subclassed directly, and then acts as a mix-in class. You can also register unrelated concrete classes (even built-in classes) and unrelated ABCs as “virtual subclasses” – these and their descendants will be considered subclasses of the registering ABC by the built-in [`issubclass()`](https://python-all.ru/3.3/library/functions.html#issubclass) function, but the registering ABC won’t show up in their MRO (Method Resolution Order) nor will method implementations defined by the registering ABC be callable (not even via [`super()`](https://python-all.ru/3.3/library/functions.html#super)). [\[1\]](https://python-all.ru/3.3/library/abc.html#id2)2425Классы, созданные с метаклассом [`ABCMeta`](https://python-all.ru/3.3/library/abc.html#abc.ABCMeta), имеют следующий метод:2627#### `register(subclass)`2829Регистрирует *подкласс* как «виртуальный подкласс» этого ABC. Например:3031```python32from abc import ABCMeta3334class MyABC(metaclass=ABCMeta):35    pass3637MyABC.register(tuple)3839assert issubclass(tuple, MyABC)40assert isinstance((), MyABC)41```4243Изменено в версии 3.3: Возвращает зарегистрированный подкласс, что позволяет использовать его в качестве декоратора класса.4445Также можно переопределить этот метод в абстрактном базовом классе:4647#### `__subclasshook__(subclass)`4849(Должен быть определён как метод класса.)5051Проверяет, считается ли *subclass* подклассом этого ABC. Это означает, что можно дополнительно настроить поведение `issubclass` без необходимости вызывать [`register()`](https://python-all.ru/3.3/library/abc.html#abc.ABCMeta.register) для каждого класса, который требуется считать подклассом ABC. (Этот метод класса вызывается из метода `__subclasscheck__()` ABC.)5253Этот метод должен возвращать `True`, `False` или `NotImplemented`. Если он возвращает `True`, то *subclass* считается подклассом этого ABC. Если он возвращает `False`, то *subclass* не считается подклассом этого ABC, даже если бы обычно им являлся. Если он возвращает `NotImplemented`, проверка на подкласс продолжается обычным механизмом.5455Для демонстрации этих концепций посмотрите на следующий пример определения ABC:5657```python58class Foo:59    def __getitem__(self, index):60        ...61    def __len__(self):62        ...63    def get_iterator(self):64        return iter(self)6566class MyIterable(metaclass=ABCMeta):6768    @abstractmethod69    def __iter__(self):70        while False:71            yield None7273    def get_iterator(self):74        return self.__iter__()7576    @classmethod77    def __subclasshook__(cls, C):78        if cls is MyIterable:79            if any("__iter__" in B.__dict__ for B in C.__mro__):80                return True81        return NotImplemented8283MyIterable.register(Foo)84```8586ABC `MyIterable` определяет стандартный метод итерирования, [`__iter__()`](https://python-all.ru/3.3/library/stdtypes.html#iterator.__iter__), как абстрактный метод. Приведённую здесь реализацию всё ещё можно вызывать из подклассов. Метод `get_iterator()` также является частью абстрактного базового класса `MyIterable`, но его не обязательно переопределять в неабстрактных производных классах.8788Определённый здесь метод класса [`__subclasshook__()`](https://python-all.ru/3.3/library/abc.html#abc.ABCMeta.__subclasshook__) говорит, что любой класс, имеющий метод [`__iter__()`](https://python-all.ru/3.3/library/stdtypes.html#iterator.__iter__) в своём [`__dict__`](https://python-all.ru/3.3/library/stdtypes.html#object.__dict__) (или в \_\_dict\_\_ одного из его базовых классов, доступном через список [`__mro__`](https://python-all.ru/3.3/library/stdtypes.html#class.__mro__)), также считается `MyIterable`.8990Наконец, последняя строка делает `Foo` виртуальным подклассом `MyIterable`, даже несмотря на то, что он не определяет метод [`__iter__()`](https://python-all.ru/3.3/library/stdtypes.html#iterator.__iter__) (он использует старый протокол итерирования, определённый через [`__len__()`](https://python-all.ru/3.3/reference/datamodel.html#object.__len__) и [`__getitem__()`](https://python-all.ru/3.3/reference/datamodel.html#object.__getitem__)). Обратите внимание, что это не сделает `get_iterator` доступным в качестве метода `Foo`, поэтому он предоставляется отдельно.9192Модуль [`abc`](https://python-all.ru/3.3/library/abc.html#module-abc) также предоставляет следующие декораторы:9394#### `@abc.abstractmethod`9596Декоратор, указывающий на абстрактные методы.9798Использование этого декоратора требует, чтобы метаклассом класса был [`ABCMeta`](https://python-all.ru/3.3/library/abc.html#abc.ABCMeta) или производный от него. Класс, у которого метакласс производный от [`ABCMeta`](https://python-all.ru/3.3/library/abc.html#abc.ABCMeta), не может быть инстанциирован, пока не будут переопределены все его абстрактные методы и свойства. Абстрактные методы можно вызывать с помощью любого из обычных механизмов вызова \`super\`. [`abstractmethod()`](https://python-all.ru/3.3/library/abc.html#abc.abstractmethod) может использоваться для объявления абстрактных методов для свойств и дескрипторов.99100Динамическое добавление абстрактных методов в класс или попытка изменить статус абстрактности метода или класса после его создания не поддерживаются. [`abstractmethod()`](https://python-all.ru/3.3/library/abc.html#abc.abstractmethod) влияет только на подклассы, производные с помощью обычного наследования; «виртуальные подклассы», зарегистрированные методом ABC `register()`, не затрагиваются.101102Когда [`abstractmethod()`](https://python-all.ru/3.3/library/abc.html#abc.abstractmethod) применяется в комбинации с другими дескрипторами методов, он должен применяться как самый внутренний декоратор, как показано в следующих примерах использования:103104```python105class C(metaclass=ABCMeta):106    @abstractmethod107    def my_abstract_method(self, ...):108        ...109    @classmethod110    @abstractmethod111    def my_abstract_classmethod(cls, ...):112        ...113    @staticmethod114    @abstractmethod115    def my_abstract_staticmethod(...):116        ...117118    @property119    @abstractmethod120    def my_abstract_property(self):121        ...122    @my_abstract_property.setter123    @abstractmethod124    def my_abstract_property(self, val):125        ...126127    @abstractmethod128    def _get_x(self):129        ...130    @abstractmethod131    def _set_x(self, val):132        ...133    x = property(_get_x, _set_x)134```135136Для корректного взаимодействия с механизмом абстрактных базовых классов дескриптор должен идентифицировать себя как абстрактный с помощью `__isabstractmethod__`. В общем случае этот атрибут должен быть `True`, если хотя бы один из методов, используемых для составления дескриптора, является абстрактным. Например, встроенное свойство Python делает эквивалент следующего:137138```python139class Descriptor:140    ...141    @property142    def __isabstractmethod__(self):143        return any(getattr(f, '__isabstractmethod__', False) for144                   f in (self._fget, self._fset, self._fdel))145```146147> **Примечание**148>149> В отличие от абстрактных методов Java, эти абстрактные методы могут иметь реализацию. Эту реализацию можно вызвать через механизм [`super()`](https://python-all.ru/3.3/library/functions.html#super) из класса, который его переопределяет. Это может быть полезно как конечная точка для вызова super во фреймворке, использующем кооперативное множественное наследование.150151#### `@abc.abstractclassmethod`152153Подкласс встроенного [`classmethod()`](https://python-all.ru/3.3/library/functions.html#classmethod), указывающий на абстрактный классовый метод. В остальном он аналогичен [`abstractmethod()`](https://python-all.ru/3.3/library/abc.html#abc.abstractmethod).154155Этот частный случай устарел, так как декоратор [`classmethod()`](https://python-all.ru/3.3/library/functions.html#classmethod) теперь корректно определяется как абстрактный при применении к абстрактному методу:156157```python158class C(metaclass=ABCMeta):159    @classmethod160    @abstractmethod161    def my_abstract_classmethod(cls, ...):162        ...163```164165Новое в версии 3.2.166167Устарело с версии 3.3: Теперь можно использовать [`classmethod`](https://python-all.ru/3.3/library/functions.html#classmethod) с [`abstractmethod()`](https://python-all.ru/3.3/library/abc.html#abc.abstractmethod), что делает этот декоратор избыточным.168169#### `@abc.abstractstaticmethod`170171Подкласс встроенного [`staticmethod()`](https://python-all.ru/3.3/library/functions.html#staticmethod), указывающий на абстрактный статический метод. В остальном он аналогичен [`abstractmethod()`](https://python-all.ru/3.3/library/abc.html#abc.abstractmethod).172173Этот частный случай устарел, так как декоратор [`staticmethod()`](https://python-all.ru/3.3/library/functions.html#staticmethod) теперь корректно определяется как абстрактный при применении к абстрактному методу:174175```python176class C(metaclass=ABCMeta):177    @staticmethod178    @abstractmethod179    def my_abstract_staticmethod(...):180        ...181```182183Новое в версии 3.2.184185Устарело с версии 3.3: теперь [`staticmethod`](https://python-all.ru/3.3/library/functions.html#staticmethod) можно использовать с [`abstractmethod()`](https://python-all.ru/3.3/library/abc.html#abc.abstractmethod), что делает этот декоратор избыточным.186187#### `@abc.abstractproperty(fget=None, fset=None, fdel=None, doc=None)`188189Подкласс встроенной [`property()`](https://python-all.ru/3.3/library/functions.html#property), указывающий на абстрактное свойство.190191Использование этой функции требует, чтобы метакласс класса был [`ABCMeta`](https://python-all.ru/3.3/library/abc.html#abc.ABCMeta) или производным от него. Класс, метакласс которого является производным от [`ABCMeta`](https://python-all.ru/3.3/library/abc.html#abc.ABCMeta), невозможно инстанцировать, пока все его абстрактные методы и свойства не будут переопределены. Абстрактные свойства можно вызывать с помощью любого из стандартных механизмов вызова 'super'.192193Этот частный случай устарел, так как декоратор [`property()`](https://python-all.ru/3.3/library/functions.html#property) теперь правильно распознается как абстрактный при применении к абстрактному методу:194195```python196class C(metaclass=ABCMeta):197    @property198    @abstractmethod199    def my_abstract_property(self):200        ...201```202203В приведённом выше примере определяется свойство только для чтения; можно также определить абстрактное свойство для чтения и записи, пометив один или несколько базовых методов как абстрактные.204205```python206class C(metaclass=ABCMeta):207    @property208    def x(self):209        ...210211    @x.setter212    @abstractmethod213    def x(self, val):214        ...215```216217Если абстрактны только некоторые компоненты, то для создания конкретного свойства в подклассе нужно обновить только эти компоненты.218219```python220class D(C):221    @C.x.setter222    def x(self, val):223        ...224```225226Устарело с версии 3.3: теперь [`property`](https://python-all.ru/3.3/library/functions.html#property), `property.getter()`, `property.setter()` и `property.deleter()` можно использовать с [`abstractmethod()`](https://python-all.ru/3.3/library/abc.html#abc.abstractmethod), что делает этот декоратор избыточным.227228Сноски229230| [\[1\]](https://python-all.ru/3.3/library/abc.html#id1) | Программистам на C++ следует отметить, что концепция виртуального базового класса в Python отличается от C++. |231| --- | --- |232