This is almost a duplicate of Exclude some attributes from fields method of dataclass.
I have a dataclass
that needs some extra attributes, which should not be considered as fields, that are derived from the fields during __post_init__
. (In particular, they are not InitVar
's!)
Since I type check my code, I want to add type hints for these attributes:
@dataclass
class MyDataClass:
field0: int
field1: int
_: KW_ONLY
fieldN: int
# internal/derived attribute that shouldn't be considered as _fields_
attr0: int # we still want type hints for obvious reasons!
attr1: int # These are not InitVars!
However, this will make them fields. I tried adding single/double underscores, which didn't work. I considered making these @properties
, but then where would you type hint the necessary self._attr0
? I guess a @cached_property
could work, but it's an unsatisfying answer.
Since dataclasses make real use in runtime of the typed variables, and you just want these to be set at static type checking time, probably the simplest idea is declare the fields in a way they are only "seen" at type-checking time.
This way, the dataclass machinery won't know about them and won't create the fields, but when using them, the static type-checking tools will. The constante type.TYPE_CHECKING
can be used for such a declaration:
import typing
from dataclasses import dataclass
...
@dataclass
class MyDataClass:
field0: int
field1: int
_: KW_ONLY
fieldN: int
if typing.TYPE_CHECKING:
# internal/derived attribute that shouldn't be considered as _fields_
attr0: int # we still want type hints for obvious reasons!
attr1: int # These are not InitVars!
So, while that would be straightforward, from the feedback in the comments, it looks like the special-casing mypy uses to figure out dataclasses simply assume these are fields anyway, and require them to be present when instantiating MyDataClass
.
While it would be possible to create a mechanism to remove the fields from the class body and annotation before calling the @dataclass
decorator, by creating an intermediary decorator - that would not help either: again, the fields would be visible to MyPy and it would require those to be present when creating the class, not knowing they are real fields.
Just make them properties, and for type-hinting the inner self._attr0
attribute, just allow typing inference to do it, or typing.cast
to force it when setting:
class MyDataclass:
...
def __post_init__(self):
self._attr0 = ... # expression using existing parameters and attributes.
# Static typing _SHOULD_ know how to infer its type. # but if it does not, force the type with cast:
self._attr0 = typing.cast(int, <expression>)
@property
def attr0(self) -> int:
return self._attr0