Preliminary note: The first three examples provided all work. My question is: If I declare dataclasses that are only used once inside another dataclass, can I avoid the "proper" declaration of the nested dataclass in favour of an "inline" declaration?
I want to use nested dataclasses because it makes attribute access in my IDE simpler, i.e. I want to be able to use dot notation like MyNestedDataclass.
and my IDE will suggest group_1
and group_2
.
I want to define a nested dict and make use of Dataclass's feature for dot-notation - mainly because my type checker then suggests the fields. This is the data structure I aim for:
my_nested_dict = {
"group_1": {
"variable_1a":10,
"variable_1b":True,
},
"group_2": {
"variable_2a":"foo",
}
}
Currently, I am doing this:
@dataclass
class Group1:
variable_1a: int = 10
variable_1b: bool = True
@dataclass
class Group2:
variable_2a: str = "foo"
@dataclass
class MyNestedDataclass:
group_1: Group1
group_2: Group2
I have tried this pattern, but it leads to my type checker not knowing which keys should be allowed in MyNestedDataclass.group_1
and MyNestedDataclass.group2
, and me not being able to access it like MyNestedDataclass.group_1.variable_1a
:
@dataclass
class MyNestedDataclass:
group_1: dict[str, Any] = field(default_factory=lambda:{
"variable_1a":10,
"variable_1b":True,
})
group_2: field(default_factory=lambda:{
"variable_2a":"foo",
})
It seems very unlikely, but is there something like this:
@dataclass
class MyNestedDataclass:
group_1: Group1 = field(default_factory=lambda: dataclass(
variable_1a: int = 10
variable_1b: bool = True
))
group_2: Group2= field(default_factory=lambda: dataclass(
variable_2a: str = "foo"
))
Is it possible to have an inline-definition of a dataclass in Python?
Short answer: No, not at type-checking time.
It is possible to create a class, and thus a dataclass, at runtime with type()
:
>>> from dataclasses import dataclass
>>> C = dataclass(type('C', (), {'__annotations__': {'a': int, 'b': str}, 'a': 0, 'b': 'lorem'}))
>>> help(C.__init__)
Help on function __init__ in module __main__:
__init__(self, a: int = 0, b: str = 'lorem') -> None
Initialize self. See help(type(self)) for accurate signature.
However, the specification doesn't require type checkers to support it. In fact, it only ever mentions the class
-based syntax.
A type checker (in your case, Pyright) might or might not choose to add this extra support. You can open a feature request, but such a request is likely to be rejected, in my experience.