Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-74690: Document changes made to runtime-checkable protocols in 3.12 #103348

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
""""""""""""""""""""""""

Expand Down
35 changes: 35 additions & 0 deletions Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,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
------

Expand All @@ -437,6 +439,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
---

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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.