Skip to content

Commit

Permalink
PEP 767: Include __init_subclass__ in initialization (#4181)
Browse files Browse the repository at this point in the history
  • Loading branch information
Enegg authored Jan 8, 2025
1 parent a9cb879 commit f57cdbe
Showing 1 changed file with 28 additions and 28 deletions.
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.protocol = 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

0 comments on commit f57cdbe

Please sign in to comment.