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