Search code examples
pythonjsonhttpstructpython-dataclasses

Is it possible to group variables in a python dataclass?


I have searched but found no good answer, so i'll make a post of it :)

I'm currently creating a python module which uses a http get request to fetch a object with a bunch of data which is structured like this.

  • Main group
    • Group 1
      • data1
      • data2
    • Group 2
      • data1
      • data2
    • Group 3
      • data1
      • data2

I have created a dataclass which just lists all these variables like

@dataclass
class MyData:
  grp1_data1: str
  grp1_data2: str
  grp2_data1: str
  grp2_data2: str
  grp3_data1: str
  grp3_data2: str

@classmethod
def from_dict(cls, data: dict) -> "MyData":
    return cls(
      grp1_data1=data["Main group"]["Group 1"]["data1"],
      grp1_data2=data["Main group"]["Group 1"]["data2"],
      # And so on ...
    )

What I'm in search for is a way to group the variables inside the dataclass similar to a struct so that i don't need to mix group name and data name in the variable name.

I'm quite new to python and I don't know what kind of such group functionalities that work with dataclasses, if there is any?

I would like to be able to write something like grp1.data1=data["Main group"]["Group 1"]["data1"] or similar.


Solution

  • It is possible to create multilevel dataclasses to do what you want (perhaps not as elegant as C-type struct's, but it works) using class composition:

    @dataclass
    class Top:
        
        @dataclass
        class Child:
            data1: str
            data2: str
                
        Group1: Child
        Group2: Child
        Group3: Child
            
            
    inst = Top(
        Group1=Top.Child('a','b'),
        Group2=Top.Child('x', 'y'),
        Group3=Top.Child('101', '102')
    )
    
    # check it:
    @dataclass
    class Top:
        
        @dataclass
        class Child:
            data1: str
            data2: str
                
        Group1: Child
        Group2: Child
        Group3: Child
            
    
    # create an instance
    inst = Top(
        Group1=Top.Child('a','b'),
        Group2=Top.Child('x', 'y'),
        Group3=Top.Child('101', '102')
    )
    
    # check it:
    assert inst.Group2.data2 == 'y'
    

    The key is you have to define all the child members as dataclasses as well (or more correctly just as classes). You can define the child class(es) in place (like above) or separately.