Have a nested dictionary.
stock_price = {'lastPrice': 129.1,
'open': 126.57,
'close': 0,
'intraDayHighLow': {'min': 126.4, 'max': 129.55, 'value': 129.1},
'weekHighLow': {'min': 49.7, 'minDate': '26-Jun-2023',
'max': 142.9,
'maxDate': '30-Apr-2024',
'value': 129.1},
}
…which is converted to a dataclass, as follows.
from dataclasses import dataclass
def create_dataclass_from_dict(data_dict: dict, class_name:str):
fields = {}
for key, value in data_dict.items():
if isinstance(value, dict):
nested_class_name = key.capitalize()
nested_class = create_dataclass_from_dict(value, class_name=nested_class_name)
fields[key] = nested_class
else:
fields[key] = value
return dataclass(type(class_name, (), fields))
….but when I see the dict of the instance, it shows an empty dictionary…
Stock = create_dataclass_from_dict(stock_price, 'Stock')
my_stock = Stock()
my_stock.weekHighLow.minDate # works '26-Jun-2023'
my_stock.__dict__ # gives {}
…and so not able to convert it back to a dictionary using the following code:
import json
def to_dict(obj):
return json.loads(json.dumps(obj, default=lambda o: o.__dict__))
to_dict(my_stock) # gives {}
Where am I going wrong? Why is the .__dict__
empty?
1
Creating the dataclass, why is __dict__
empty
type(class_name, (), fields)
This creates a class which has fields
as class attributes. They will be present in Stock.__dict__
, but not in my_stock.__dict__
for any instance my_stock
of Stock
.
Using dataclass()
with a class created like this will not actually create the dataclass fields.
For example, dataclass("Stock", (), {"last_price": 129.1})
is like writing
@dataclass
class Stock:
last_price = 129.1
but a dataclass field requires a type annotation, like
@dataclass
class Stock:
last_price: float = 129.1
which would create a field called last_price
with a default value 129.1
.
To create a dataclass dynamically, use dataclasses.make_dataclass
instead.
Converting a dataclass instance to a dictionary
To convert a dataclass to a dictionary, you should use dataclasses.asdict
, not rely on the __dict__
attribute.
This is explained in more detail in this answer.
1