0

I have the following issue. I want to convert a complex object to a json dictionary. I am unable to do it directly so I end up using json.dumps() to make the object into a string first and then load that string with json.loads().

I was expecting to be able to do it with json.dump(), however that requires that I put it into a file-like object which seems like an extra hoop to go through when wanting to get a dict data structure.

Is there a way to eliminate the conversion to string and then the load without creating an object that exposes a write method?

Sample code:

import json

class Location():
    def __init__(self, lat, lon):
         self.lat = lat
         self.lon = lon

class WeatherResponse():
     def __init__(self,
             state: str,
             temp: float,
             pressure: float,
             humidity: float,
             wind_speed: float,
             wind_direction: float,
             clouds: str,
             location: Location):
        self.state = state
        self.temp = temp
        self.pressure = pressure
        self.humidity = humidity
        self.wind_speed = wind_speed
        self.wind_direction = wind_direction
        self.clouds = clouds
        self.location = location

 weather = WeatherResponse(state = "Meteorite shower",
                      temp = 35.5,
                      pressure = 1,
                      humidity = "Wet",
                      wind_speed = 3,
                      wind_direction = 150,
                      clouds = "Cloudy",
                      location = Location(10, 10))

 weather_json = json.dump(weather) #Needs a file like object

 weather_string = json.dumps(weather, default = lambda o: o.__dict__)
 weather_dict = json.loads(weather_string)

 print(weather_dict)
Iustinian Olaru
  • 1,231
  • 1
  • 13
  • 33
  • Does this answer your question? [Convert dynamic python object to json](https://stackoverflow.com/questions/7408647/convert-dynamic-python-object-to-json) – Ramon Medeiros Feb 07 '20 at 10:55
  • Why dont you do just `weather_json = weather.__dict__`? – sanyassh Feb 07 '20 at 10:57
  • No, the answer for this question uses the json.dumps method which I also exemplified in my above sample code. – Iustinian Olaru Feb 07 '20 at 10:57
  • 1
    What was the problem with `json.dumps` again? – mkrieger1 Feb 07 '20 at 10:58
  • @sanyash the __dict__ method works for simple objects. In the case of complex objects with other objects inside it returns the memory address. – Iustinian Olaru Feb 07 '20 at 10:58
  • The variable names you're using are quite misleading. The second `weather_json` is actually a `dict` not a JSON string. But to answer your question: to convert a python object to a JSON string without writing it to file you need to use `json.dumps` instead of `json.dump` and that's all. I honestly think that you confuse the terms JSON and dict in this case, because you want to convert an arbitrary object into a nested dictionary. For that I'd recommend using serializer libraries like pydantic or marshmallow. – Szabolcs Feb 07 '20 at 11:16
  • 1
    @Szabolcs I think I made it more confusing than it is but you gave me more clarity. I want to convert the object into a nested dictionary, and I'm using the json module to do it. My problem is that I don't want to have to convert the object first to a string of a nested dict and then to a dict by loading, instead I want to convert it straight to a nested dictionary. The __dict__ method does not work as it does not unwrap the Location object in this case. – Iustinian Olaru Feb 07 '20 at 11:31

1 Answers1

1

So after clarifying your requirements, it seems like you would like to convert an arbitrary class to a nested dict and not to a JSON string.

In that case I suggest you to use some kind of a serializer/deserializer library such as pydantic or marshmallow.

An example of your implementation in pydantic would look like this:

import pydantic


class Location(pydantic.BaseModel):
    lat: float
    lon: float


class WeatherResponse(pydantic.BaseModel):
    state: str
    temp: float
    pressure: float
    humidity: str
    wind_speed: float
    wind_direction: float
    clouds: str
    location: Location


weather = WeatherResponse(
    state="Meteorite shower",
    temp=35.5,
    pressure=1,
    humidity="Wet",
    wind_speed=3,
    wind_direction=150,
    clouds="Cloudy",
    location=Location(lat=10, lon=10),
)

weather_dict = weather.dict()
# {'state': 'Meteorite shower', 'temp': 35.5, 'pressure': 1.0, 'humidity': 'Wet', 'wind_speed': 3.0, 'wind_direction': 150.0, 'clouds': 'Cloudy', 'location': {'lat': 10.0, 'lon': 10.0}}

For advanced usage please check out the provided links.

Hope it helps!

Szabolcs
  • 3,990
  • 18
  • 38