0

My JSON reads:

{
    "employee_1": {"name": "Sarah"},
    "employee_2": {"name": "Emma"}
}

Which is created as:

class Employee:
    def __init__(self, name):
        self.name = name


employees = {}
employees["employee_1"] = Employee("Sarah")
employees["employee_2"] = Employee("Emma")
json_str = json.dumps(employees, 
                      default=lambda x: x.__dict__)

I write this JSON to a file and later on, load it from the file. However, the loaded object is deserialized as a dictionary of dictionaries, rather than a dictionary of Employees.

loaded_employees = json.loads(json_str)

print(type(employees["employee_1"]))
print(type(loaded_employees["employee_1"]))

Output is:

<class '__main__.Employee'>
<class 'dict'>

I want the loaded employee_1 to be of type Employee, exactly as it was when persisting to JSON.

I think this should be achievable leveraging object_hook; this SO answer or object_hook documentation explain how to use it for "flat" type object (for the lack of a better word), though not sure how I can use it for a dictionary of custom type as is here.

Dr. Strangelove
  • 2,725
  • 3
  • 34
  • 61
  • 2
    JSON can't store class information. – Barmar Aug 11 '21 at 00:43
  • Use a lib like marshmallow – drum Aug 11 '21 at 00:44
  • JSON is text based and so they cant store classes which have things like methods. Its like this because sometimes you want to use this data from other files which might not have this class and so they cant just make a way to dump it into a string. JSON stands for JavaScript Object Notation which doesnt have anything but text so it wouldnt make sense to be able to have a class. What I do is just remake teh class – smal Aug 11 '21 at 00:46
  • If you know that the JSON contains `Employee` objects, you can loop over the dictionary and convert them to `Employee`. – Barmar Aug 11 '21 at 00:46
  • I know in C# you can simply convert this JSON back to object if you specify your JSON is of type `Dictionary`; like `JsonConvert.DeserializeObject>(json)` – Dr. Strangelove Aug 11 '21 at 00:50
  • Python's object serialization feature is called [pickling](https://www.tutorialspoint.com/object_oriented_python/object_oriented_python_serialization.htm), but it's not JSON. Also see https://stackoverflow.com/questions/2259270/pickle-or-json – jarmod Aug 11 '21 at 01:09
  • Thanks for the suggestion, interoperability and human-readability is a requirement of my (de)serialization; hence I am guessing pickling would not help much. – Dr. Strangelove Aug 11 '21 at 01:12
  • There are folks who have built serialization formats that allow type data to be represented (yaml can do this; so can EDN). There wouldn't be any _need_ for that if JSON could do it. (Okay, EDN adds other niceties too, but tagged content is certainly one of them). – Charles Duffy Aug 11 '21 at 04:08

2 Answers2

0

I would say what you want to do is make your init statement take in a dictionary like it does now and then create the classes by looping over your dictionary or list from json. You will also have to make a specific dump function that will dump all the variables in the object into a dictionary to move into json.

smal
  • 177
  • 10
0

Convert the dictionary elements to Employee after loading the JSON.

employees = json.loads(json_str)
for k, v in employees.items():
    employees[k] = Employee(**v)
Dr. Strangelove
  • 2,725
  • 3
  • 34
  • 61
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thanks for the suggestion. My only concern about this approach is it will lead to a wordy and less-portable solution in a real-world application. For instance, if `Employee` has a member that is a dictionary of another type (e.g., `Managers`), then I would need to repeat the same process for that member. And all of that implementation would need to be updated anytime the `Employee` type is modified. – Dr. Strangelove Aug 11 '21 at 02:01
  • That's true, there's no really general solution with JSON. – Barmar Aug 11 '21 at 02:21