Creating nested dataclass objects in Python - GeeksforGeeks

29 Aug, 2020
Dataclasses is an inbuilt Python module which contains decorators and functions for automatically adding special methods like __init__() and __repr__() to user-defined classes.
Dataclass Object is an object built into the Dataclasses module. This function is used as a decorator to add special methods directly to a user-defined class. This decorator examines class to find fields(a class variable that contains a type annotation). Then the dataclass decorator adds special methods.
Syntax:
@dataclass
class user_defined_class:

Here, we’ll tackle the idea of having nested dataclass objects in our program. Even though dataclasses are easy to use, they still increase the complexity of the program by one bar, and nesting such objects can be seen a little challenging but here we’ll take on each scenario and how to handle it.
Carefully examine the following code:
@dataclassclass A:    a: int    b: str  @dataclassclass B:    c: str    d: A
Starting with class A, it is being decorated by a dataclass. This class is then being nested within class B as a field of B which also is being decorated by a dataclass object. So far this code just shows the nesting of dataclass objects, next we discuss how do we employ such implementation.
# importing modulefrom dataclasses import dataclass  @dataclassclass A:    a: int    b: str  @dataclassclass B:    c: str    d: A  # FIRST APPROACH# creating object for class b with following values # c ='hello'# a = 4# b ='bye'data ={'c':'hello', 'd':{'a':4, 'b':'bye'}}b = B(**data)print (b)  # SECOND APPROACHdata ={'c':'hello', 'd': A(**{'a':4, 'b':'bye'})}c = B(**data)print(c)
Output:
B(c='hello', d={'a': 4, 'b': 'bye'})
B(c='hello', d=A(a=4, b='bye'))
The problem with the first approach is that the output gives no idea about the nested object or the class A and its attributes, and if that is ones requirement then we are good to go. The second approach does the trick but it seems tedious if you have multiple nested objects in your dataclass objects, not just this, with increase in number of nested objects the complexity of the program will also increase and so will the method for calling them. Thus, we require a way to achieve the output of the second approach but without making the calling and initializing process complex.
The above problem can be resolved by wrapping generated __init__() method that will check for parameters passed to kwargs, check if any field belongs to a dataclass field type and if it does generate the nested object prior to the original __init__().
What this means is shown below :
from dataclasses import dataclass, is_dataclass  # decorator to wrap original __init__def nested_deco(*args, **kwargs):          def wrapper(check_class):                  # passing class to investigate        check_class = dataclass(check_class, **kwargs)        o_init = check_class.__init__                  def __init__(self, *args, **kwargs):                          for name, value in kwargs.items():                                  # getting field type                ft = check_class.__annotations__.get(name, None)                                  if is_dataclass(ft) and isinstance(value, dict):                    obj = ft(**value)                    kwargs[name]= obj                o_init(self, *args, **kwargs)        check_class.__init__=__init__                  return check_class          return wrapper(args[0]) if args else wrapper    @dataclassclass A:    a: int    b: str  @nested_decoclass B:    c: str    d: A    data ={'c':'hello', 'd':{'a':4, 'b':'bye'}}b = B(**data)print (b)
Output:
B(c='hello', d=A(a=4, b='bye'))
Note that apart from problems generated by __init__() this also doesn’t allow __init__=false to be returned to the code.
python-modules
python-oop-concepts
Python
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Python Dictionary
Read a file line by line in Python
How to Install PIP on Windows ?
Enumerate() in Python
Different ways to create Pandas Dataframe
Iterate over a list in Python
Python String | replace()
*args and **kwargs in Python
Reading and Writing to text files in Python
Create a Pandas DataFrame from Lists