Сообщить об ошибке.

Декоратор @runtime_checkable модуля typing в Python

Отмечает класс, как протокол времени выполнения

Синтаксис:

from typing import runtime_checkable

@runtime_checkable

Параметры:

  • нет.

Описание:

Декоратор @runtime_checkable() модуля typing отмечает класс протокола как протокол времени выполнения.

Такой протокол можно использовать с функциями isinstance() и issubclass(). Декоратор вызывает исключение TypeError при применении его к непротокольному классу. Такое поведение позволяет выполнять простую структурную проверку, очень похожую на "актера с одной ролью" в collections.abc, например Iterable.

Пример:

@runtime_checkable
class Closable(Protocol):
    def close(self): ...

assert isinstance(open('/some/file'), Closable)

@runtime_checkable
class Named(Protocol):
    name: str

import threading
assert isinstance(threading.Thread(name='Bob'), Named)

Примечание 1. Декоратор @runtime_checkable() будет проверять только наличие необходимых методов или атрибутов, а не их сигнатуры или типы. Например, ssl.SSLObject - это класс, поэтому он проходит проверку issubclass() для Callable. Однако метод ssl.SSLObject.__init__ существует только для того, чтобы вызвать TypeError с более информативным сообщением, что делает невозможным вызов (создание экземпляра) ssl.SSLObject.

Примечание 2. Проверка isinstance() для протокола, проверяемого во время выполнения, может быть на удивление медленной по сравнению с проверкой isinstance() для непротокольного класса. Для структурных проверок в коде, чувствительных к производительности нужно рассмотреть возможность использования альтернативных идиом, такие как вызовы hasattr().

Изменено в Python 3.12: внутренняя реализация isinstance() при проверке протоколов теперь использует Inspect.getattr_static() для поиска атрибутов (ранее использовался hasattr()). В результате некоторые объекты, которые раньше считались экземплярами протокола, больше не могут считаться экземплярами этого протокола в Python 3.12+, и наоборот. Это изменение вряд ли затронет большинство пользователей.

Изменено в Python 3.12: члены протокола, проверяемого во время выполнения, теперь считаются "замороженными" во время выполнения, как только класс был создан. Атрибуты Monkey-Patching в протоколе, проверяемом во время выполнения, по-прежнему будут работать, но не окажут влияния на проверки isinstance(), сравнивающие объекты с протоколом.

>>> from typing import Protocol, runtime_checkable
>>> @runtime_checkable
>>> class HasX(Protocol):
>>>     x = 1

>>> class Foo: ...

>>> f = Foo()
>>> isinstance(f, HasX)
# False
>>> f.x = 1
>>> isinstance(f, HasX)
# True
>>> HasX.y = 2
# без изменений, хотя HasX теперь также имеет атрибут 'y'
>>> isinstance(f, HasX)
# True