]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-74690: Document changes made to runtime-checkable protocols in 3.12 (#103348)
authorAlex Waygood <Alex.Waygood@Gmail.com>
Fri, 7 Apr 2023 21:06:37 +0000 (22:06 +0100)
committerGitHub <noreply@github.com>
Fri, 7 Apr 2023 21:06:37 +0000 (22:06 +0100)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Doc/library/typing.rst
Doc/whatsnew/3.12.rst
Misc/NEWS.d/next/Library/2023-04-07-15-09-26.gh-issue-74690.0f886b.rst [new file with mode: 0644]
Misc/NEWS.d/next/Library/2023-04-07-15-15-40.gh-issue-74690.un84hh.rst [new file with mode: 0644]

index 8728ca7b6b358ccb25197cb207f8774b6ea84029..03ff259bbdf75f87ca2b0bc69d40204a29ddc367 100644 (file)
@@ -1598,15 +1598,6 @@ These are not used in annotations. They are building blocks for creating generic
       import threading
       assert isinstance(threading.Thread(name='Bob'), Named)
 
-   .. versionchanged:: 3.12
-      The internal implementation of :func:`isinstance` checks against
-      runtime-checkable protocols now uses :func:`inspect.getattr_static`
-      to look up attributes (previously, :func:`hasattr` was used).
-      As a result, some objects which used to be considered instances
-      of a runtime-checkable protocol may no longer be considered instances
-      of that protocol on Python 3.12+, and vice versa.
-      Most users are unlikely to be affected by this change.
-
    .. note::
 
         :func:`!runtime_checkable` will check only the presence of the required
@@ -1628,6 +1619,24 @@ These are not used in annotations. They are building blocks for creating generic
 
    .. versionadded:: 3.8
 
+   .. versionchanged:: 3.12
+      The internal implementation of :func:`isinstance` checks against
+      runtime-checkable protocols now uses :func:`inspect.getattr_static`
+      to look up attributes (previously, :func:`hasattr` was used).
+      As a result, some objects which used to be considered instances
+      of a runtime-checkable protocol may no longer be considered instances
+      of that protocol on Python 3.12+, and vice versa.
+      Most users are unlikely to be affected by this change.
+
+   .. versionchanged:: 3.12
+      The members of a runtime-checkable protocol are now considered "frozen"
+      at runtime as soon as the class has been created. Monkey-patching
+      attributes onto a runtime-checkable protocol will still work, but will
+      have no impact on :func:`isinstance` checks comparing objects to the
+      protocol. See :ref:`"What's new in Python 3.12" <whatsnew-typing-py312>`
+      for more details.
+
+
 Other special directives
 """"""""""""""""""""""""
 
index 3a12fb20c43c51156a4798db13d70353538bf6e2..66e40ef7326cc04721b669469e611bcaaadf9669 100644 (file)
@@ -422,6 +422,8 @@ tempfile
 The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter
 *delete_on_close* (Contributed by Evgeny Zorin in :gh:`58451`.)
 
+.. _whatsnew-typing-py312:
+
 typing
 ------
 
@@ -441,6 +443,39 @@ typing
   vice versa. Most users are unlikely to be affected by this change.
   (Contributed by Alex Waygood in :gh:`102433`.)
 
+* The members of a runtime-checkable protocol are now considered "frozen" at
+  runtime as soon as the class has been created. Monkey-patching attributes
+  onto a runtime-checkable protocol will still work, but will have no impact on
+  :func:`isinstance` checks comparing objects to the protocol. For example::
+
+      >>> 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
+      >>> isinstance(f, HasX)  # unchanged, even though HasX now also has a "y" attribute
+      True
+
+  This change was made in order to speed up ``isinstance()`` checks against
+  runtime-checkable protocols.
+
+* The performance profile of :func:`isinstance` checks against
+  :func:`runtime-checkable protocols <typing.runtime_checkable>` has changed
+  significantly. Most ``isinstance()`` checks against protocols with only a few
+  members should be at least 2x faster than in 3.11, and some may be 20x
+  faster or more. However, ``isinstance()`` checks against protocols with seven
+  or more members may be slower than in Python 3.11. (Contributed by Alex
+  Waygood in :gh:`74690` and :gh:`103193`.)
+
 sys
 ---
 
diff --git a/Misc/NEWS.d/next/Library/2023-04-07-15-09-26.gh-issue-74690.0f886b.rst b/Misc/NEWS.d/next/Library/2023-04-07-15-09-26.gh-issue-74690.0f886b.rst
new file mode 100644 (file)
index 0000000..0a103ae
--- /dev/null
@@ -0,0 +1,3 @@
+The members of a runtime-checkable protocol are now considered "frozen" at
+runtime as soon as the class has been created. See
+:ref:`"What's new in Python 3.12" <whatsnew-typing-py312>` for more details.
diff --git a/Misc/NEWS.d/next/Library/2023-04-07-15-15-40.gh-issue-74690.un84hh.rst b/Misc/NEWS.d/next/Library/2023-04-07-15-15-40.gh-issue-74690.un84hh.rst
new file mode 100644 (file)
index 0000000..48f11aa
--- /dev/null
@@ -0,0 +1,8 @@
+The performance of :func:`isinstance` checks against
+:func:`runtime-checkable protocols <typing.runtime_checkable>` has been
+considerably improved for protocols that only have a few members. To achieve
+this improvement, several internal implementation details of the
+:mod:`typing` module have been refactored, including
+``typing._ProtocolMeta.__instancecheck__``,
+``typing._is_callable_members_only``, and ``typing._get_protocol_attrs``.
+Patches by Alex Waygood.