Reputation: 1179
I'm learning about dataclass
and I'm having problem with understanding why __annotations__
doesn't give the fields from the parent class. See the example below:
import dataclasses as dc
@dc.dataclass
class B:
a: int
B.__annotations__
# returns {'a': int}
C = dc.make_dataclass("c", fields=["w"], bases=(B,))
C.__annotations__
# returns {'w': 'typing.Any'} (without a)
Upvotes: 1
Views: 1612
Reputation: 20237
__annotations__
doesn't give you the type annotations of the parent class because it is supposed to only hold the annotations that were defined in the class body of itself. There is a specific function that returns all annotations of a class, including those of its parents, called typing.get_type_hints
:
This is often the same as
obj.__annotations__
. [...] For a class C, return a dictionary constructed by merging all the__annotations__
alongC.__mro__
in reverse order.
One thing to keep in mind when using it with your specific example is that dataclasses use a lot of black magic to construct classes, and it will break in finding all type hints if some fields are untyped in the make_dataclass
definition (filed as a bug here):
import dataclasses as dc
from typing import Any, get_type_hints
@dc.dataclass
class B:
a: int
get_type_hints(B)
# returns {'a': <class 'int'>}
# fields=["w"] should be equivalent, but get_type_hints doesn't like it. Bug, maybe?
C = dc.make_dataclass("C", fields=[("w", Any)], bases=(B,))
typing.get_type_hints(C)
# returns {'a': <class 'int'>, 'w': typing.Any}
But as user2357112 pointed out, you might be best advised to use the dataclasses.fields
function, which returns the fields that the dataclass decorator builds based on the annotations of the dataclass and its bases. This is usually what you would want to work with when analyzing dataclasses, and it contains all the information you need plus some more.
Additionally, it works with the shorthand definition for fields in make_dataclass
that you used initially, and cleans out pseudo-fields:
dc.fields(D)
# returns a tuple of
Field(name='a',type=<class 'int'>,default=<dataclasses._MISSING_TYPE object at 0x7f103d9985c0>,default_factory=<dataclasses._MISSING_TYPE object at 0x7f103d9985c0>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD)
# and
Field(name='w',type=typing.Any,default=<dataclasses._MISSING_TYPE object at 0x7f103d9985c0>,default_factory=<dataclasses._MISSING_TYPE object at 0x7f103d9985c0>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD)
Upvotes: 2