@@ -98,8 +98,7 @@ Today, there are three major ways of achieving read-only attributes, honored by
9898Protocols
9999---------
100100
101- A read-only attribute ``name: T `` on a :class: `~typing.Protocol ` in principle
102- defines two requirements:
101+ Suppose a :class: `~typing.Protocol ` member ``name: T `` defining two requirements:
103102
1041031. ``hasattr(obj, "name") ``
1051042. ``isinstance(obj.name, T) ``
@@ -251,7 +250,12 @@ Initialization
251250
252251Assignment to a read-only attribute can only occur in the class declaring the attribute.
253252There is no restriction to how many times the attribute can be assigned to.
254- The assignment must be allowed in the following contexts:
253+ Depending on the kind of the attribute, they can be assigned to at different sites:
254+
255+ Instance Attributes
256+ '''''''''''''''''''
257+
258+ Assignment to an instance attribute must be allowed in the following contexts:
255259
256260* In ``__init__ ``, on the instance received as the first parameter (likely, ``self ``).
257261* In ``__new__ ``, on instances of the declaring class created via a call
@@ -267,9 +271,6 @@ Additionally, a type checker may choose to allow the assignment:
267271* In ``@classmethod ``\ s, on instances of the declaring class created via
268272 a call to the class' or super-class' ``__new__ `` method.
269273
270- Note that a child class cannot assign to any read-only attributes of a parent class
271- in any of the aforementioned contexts, unless the attribute is redeclared.
272-
273274.. code-block :: python
274275
275276 from collections import abc
@@ -332,6 +333,25 @@ in any of the aforementioned contexts, unless the attribute is redeclared.
332333 self .numerator, self .denominator = f.as_integer_ratio()
333334 return self
334335
336+ Class Attributes
337+ ''''''''''''''''
338+
339+ Read-only class attributes are attributes annotated as both ``ReadOnly `` and ``ClassVar ``.
340+ Assignment to such attributes must be allowed in the following contexts:
341+
342+ * At declaration in the body of the class.
343+ * In ``__init_subclass__ ``, on the class object received as the first parameter (likely, ``cls ``).
344+
345+ .. code-block :: python
346+
347+ class URI :
348+ protocol: ReadOnly[ClassVar[str ]] = " "
349+
350+ def __init_subclass__ (cls , protocol : str = " " ) -> None :
351+ cls .protocol = protocol
352+
353+ class File (URI , protocol = " file" ): ...
354+
335355 When a class-level declaration has an initializing value, it can serve as a `flyweight <https://en.wikipedia.org/wiki/Flyweight_pattern >`_
336356default for instances:
337357
@@ -367,8 +387,8 @@ protocols or ABCs)::
367387Subtyping
368388---------
369389
370- Read-only attributes are covariant. This has a few subtyping implications .
371- Borrowing from :pep: `705#inheritance `:
390+ The inability to reassign read-only attributes makes them covariant .
391+ This has a few subtyping implications. Borrowing from :pep: `705#inheritance `:
372392
373393* Read-only attributes can be redeclared as writable attributes, descriptors
374394 or class variables::
@@ -493,9 +513,6 @@ Interaction with Other Type Qualifiers
493513 This is consistent with the interaction of ``ReadOnly `` and :class: `typing.TypedDict `
494514defined in :pep: `705 `.
495515
496- An attribute annotated as both ``ReadOnly `` and ``ClassVar `` can only be assigned to
497- at declaration in the class body.
498-
499516An attribute cannot be annotated as both ``ReadOnly `` and ``Final ``, as the two
500517qualifiers differ in semantics, and ``Final `` is generally more restrictive.
501518``Final `` remains allowed as an annotation of attributes that are only implied
@@ -604,23 +621,6 @@ to allow initialization in. This however could easily result in users mistakenly
604621or purposefully breaking the aforementioned invariants. It is also a fairly
605622big ask for a relatively niche feature.
606623
607- ``ReadOnly[ClassVar[...]] `` and ``__init_subclass__ ``
608- -----------------------------------------------------
609-
610- Should read-only class variables be assignable to within the declaring class'
611- ``__init_subclass__ ``?
612-
613- .. code-block :: python
614-
615- class URI :
616- protocol: ReadOnly[ClassVar[str ]] = " "
617-
618- def __init_subclass__ (cls , protocol : str = " " ) -> None :
619- cls .foo = protocol
620-
621- class File (URI , protocol = " file" ): ...
622-
623-
624624Footnotes
625625=========
626626
0 commit comments