It is possible to type the following code in Python3.12:
class B:
pass
b = B()
class A:
a: "x"
b.c: "y"
Without b
declaration, this code throws NameError. After that, A.__annotations__
shows: {'a': 'x'}
. Annotation dicts of b
and B
are empty.
Does this mean anything? Is it just some future syntax with no effects or does the b.c
annotation end up somewhere?
Annotations for object.attribute
, object[item]
and object[sl:ice]
are permitted by the grammar:
assignment:
| NAME ':' expression ['=' annotated_rhs ]
| ('(' single_target ')'
| single_subscript_attribute_target) ':' expression ['=' annotated_rhs ]
single_target:
| single_subscript_attribute_target
| NAME
| '(' single_target ')'
single_subscript_attribute_target:
| t_primary '.' NAME !t_lookahead
| t_primary '[' slices ']' !t_lookahead
They don't have any standardized semantics in the type system, however:
The target of the annotation can be any valid single assignment target, at least syntactically (it is up to the type checker what to do with this):
class Cls: pass c = Cls() c.x: int = 0 # Annotates c.x with int. c.y: int # Annotates c.y with int. d = {} d['a']: int = 0 # Annotates d['a'] with int. d['b']: int # Annotates d['b'] with int.
— § Annotating expressions | PEP 526: Syntax for Variable Annotations
The runtime data is also not stored anywhere, as with annotations for local variables.
One exception is self.attribute
, but annotations of this kind cannot be placed directly within the class's body:
class C:
def __init__(self) -> None:
self.attribute: str
reveal_type(C().attribute) # str