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

PEP 767: Include __init_subclass__ in initialization #4181

Merged
merged 4 commits into from
Jan 8, 2025
Merged
Changes from 3 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
56 changes: 28 additions & 28 deletions peps/pep-0767.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ Today, there are three major ways of achieving read-only attributes, honored by
Protocols
---------

A read-only attribute ``name: T`` on a :class:`~typing.Protocol` in principle
defines two requirements:
Suppose a :class:`~typing.Protocol` member ``name: T`` defining two requirements:

1. ``hasattr(obj, "name")``
2. ``isinstance(obj.name, T)``
Expand Down Expand Up @@ -251,7 +250,12 @@ Initialization

Assignment to a read-only attribute can only occur in the class declaring the attribute.
There is no restriction to how many times the attribute can be assigned to.
The assignment must be allowed in the following contexts:
Depending on the kind of the attribute, they can be assigned to at different sites:

Instance Attributes
'''''''''''''''''''

Assignment to an instance attribute must be allowed in the following contexts:

* In ``__init__``, on the instance received as the first parameter (likely, ``self``).
* In ``__new__``, on instances of the declaring class created via a call
Expand All @@ -267,9 +271,6 @@ Additionally, a type checker may choose to allow the assignment:
* In ``@classmethod``\ s, on instances of the declaring class created via
a call to the class' or super-class' ``__new__`` method.

Note that a child class cannot assign to any read-only attributes of a parent class
in any of the aforementioned contexts, unless the attribute is redeclared.

.. code-block:: python

from collections import abc
Expand Down Expand Up @@ -332,6 +333,25 @@ in any of the aforementioned contexts, unless the attribute is redeclared.
self.numerator, self.denominator = f.as_integer_ratio()
return self

Class Attributes
''''''''''''''''

Read-only class attributes are attributes annotated as both ``ReadOnly`` and ``ClassVar``.
Assignment to such attributes must be allowed in the following contexts:

* At declaration in the body of the class.
* In ``__init_subclass__``, on the class object received as the first parameter (likely, ``cls``).

.. code-block:: python

class URI:
protocol: ReadOnly[ClassVar[str]] = ""

def __init_subclass__(cls, protocol: str = "") -> None:
cls.foo = protocol

class File(URI, protocol="file"): ...

When a class-level declaration has an initializing value, it can serve as a `flyweight <https://en.wikipedia.org/wiki/Flyweight_pattern>`_
default for instances:

Expand Down Expand Up @@ -367,8 +387,8 @@ protocols or ABCs)::
Subtyping
---------

Read-only attributes are covariant. This has a few subtyping implications.
Borrowing from :pep:`705#inheritance`:
The inability to reassign read-only attributes makes them covariant.
This has a few subtyping implications. Borrowing from :pep:`705#inheritance`:

* Read-only attributes can be redeclared as writable attributes, descriptors
or class variables::
Expand Down Expand Up @@ -493,9 +513,6 @@ Interaction with Other Type Qualifiers
This is consistent with the interaction of ``ReadOnly`` and :class:`typing.TypedDict`
defined in :pep:`705`.

An attribute annotated as both ``ReadOnly`` and ``ClassVar`` can only be assigned to
at declaration in the class body.

An attribute cannot be annotated as both ``ReadOnly`` and ``Final``, as the two
qualifiers differ in semantics, and ``Final`` is generally more restrictive.
``Final`` remains allowed as an annotation of attributes that are only implied
Expand Down Expand Up @@ -604,23 +621,6 @@ to allow initialization in. This however could easily result in users mistakenly
or purposefully breaking the aforementioned invariants. It is also a fairly
big ask for a relatively niche feature.

``ReadOnly[ClassVar[...]]`` and ``__init_subclass__``
-----------------------------------------------------

Should read-only class variables be assignable to within the declaring class'
``__init_subclass__``?

.. code-block:: python

class URI:
protocol: ReadOnly[ClassVar[str]] = ""

def __init_subclass__(cls, protocol: str = "") -> None:
cls.foo = protocol

class File(URI, protocol="file"): ...


Footnotes
=========

Expand Down
Loading