From c70742eb18248f023d6496a6428a776eebc77979 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Wed, 22 Mar 2023 22:40:41 +0000 Subject: [PATCH 1/2] Typing: document performance pitfalls of protocols decorated with `@runtime_checkable` --- Doc/library/typing.rst | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 80a969e6335abe..297e3bc9c51155 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1584,16 +1584,31 @@ These are not used in annotations. They are building blocks for creating generic assert isinstance(open('/some/file'), Closable) + @runtime_checkable + class HasErrNo(Protocol): + errno: int + + assert isinstance(OSError(42, 'foo'), HasErrNo) + .. note:: - :func:`runtime_checkable` will check only the presence of the required - methods, not their type signatures. For example, :class:`ssl.SSLObject` + :func:`!runtime_checkable` will check only the presence of the required + methods or attributes, not their type signatures or types. + For example, :class:`ssl.SSLObject` is a class, therefore it passes an :func:`issubclass` check against :data:`Callable`. However, the ``ssl.SSLObject.__init__`` method exists only to raise a :exc:`TypeError` with a more informative message, therefore making it impossible to call (instantiate) :class:`ssl.SSLObject`. + .. note:: + + An :func:`isinstance` check against a runtime-checkable protocol can be + surprisingly slow compared to an ``isinstance()`` check against + a non-protocol class. Consider using alternative idioms such as + :func:`hasattr` calls for structural checks in performance-sensitive + code. + .. versionadded:: 3.8 Other special directives From 7666617ed53eaa6d1dabc3e7672dec8872d9f4d8 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Thu, 23 Mar 2023 13:42:03 +0000 Subject: [PATCH 2/2] A thread named Bob --- Doc/library/typing.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 297e3bc9c51155..08ffa0310f0f23 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1585,10 +1585,11 @@ These are not used in annotations. They are building blocks for creating generic assert isinstance(open('/some/file'), Closable) @runtime_checkable - class HasErrNo(Protocol): - errno: int + class Named(Protocol): + name: str - assert isinstance(OSError(42, 'foo'), HasErrNo) + import threading + assert isinstance(threading.Thread(name='Bob'), Named) .. note::