2

How can I save this structure of Python objects into a file (preferably JSON)? And how can I load this structure from the file again?

class Nested(object):
    def __init__(self, n):
        self.name = "Nested Object: " + str(n)
        self.state = 3.14159265359

class Nest(object):
    def __init__(self):
        self.x = 1
        self.y = 2
        self.objects = []

tree = []
tree.append(Nest())
tree.append(Nest())
tree.append(Nest())

tree[0].objects.append(Nested(1))
tree[0].objects.append(Nested(2))

tree[1].objects.append(Nested(1))


tree[2].objects.append(Nested(7))
tree[2].objects.append(Nested(8))
tree[2].objects.append(Nested(9))
Gurkenkönig
  • 678
  • 15
  • 36
  • [Saving structured data with JSON](https://docs.python.org/3/tutorial/inputoutput.html#saving-structured-data-with-json) and the [json module documentation](https://docs.python.org/3/library/json.html#module-json) from the Python docs will tell you all you need to know. – i alarmed alien Aug 12 '18 at 13:20
  • 1
    top answer shows how to do it with json and with pickle https://stackoverflow.com/questions/36965507/writing-a-dictionary-to-a-text-file-in-python , in my opinion if you only ever load and save this data in python pickle is superior since it keeps the exact types whereas json can only work with primitives – AntiMatterDynamite Aug 12 '18 at 13:22
  • Possible duplicate of [Save objects into JSON or XML file in Python](https://stackoverflow.com/questions/20539999/save-objects-into-json-or-xml-file-in-python) – i alarmed alien Aug 12 '18 at 13:26
  • @AntiMatterDynamite JSON can only work with primitives out-of-the-box, but you can always write your own `JSONEncoder` and `JSONDecoder`. – André C. Andersen Aug 12 '18 at 20:44
  • 1
    Do you looking for a nested objective-Json? maybe this [link](https://stackoverflow.com/a/51315029/3702377) helps you up. – Benyamin Jafari Aug 12 '18 at 21:00
  • @AndréChristofferAndersen true, but you can do even better with making your own data structure format... the point is that you need much less code for using stuff out of the box – AntiMatterDynamite Aug 13 '18 at 06:15
  • @AntiMatterDynamite Definitely. In most cases I'd go for a library long before I coded my own encoder/decoder. I think I even called it the "hard way" in my answer. :) Nice to have options though. – André C. Andersen Aug 13 '18 at 06:28

2 Answers2

2

Thanks to the reference to "pickle" I found a well working very simple solution to save my array of objects:

pickle

import pickle

pickle.dump( tree, open( "save.p", "wb" ) )

loaded_objects = pickle.load( open( "save.p", "rb" ) )

jsonpickle

import jsonpickle

frozen = jsonpickle.encode(tree)

with open("save.json", "w") as text_file:
    print(frozen, file=text_file)

file = open("save.json", "r") 
loaded_objects = jsonpickle.decode(file.read())
Gurkenkönig
  • 678
  • 15
  • 36
1

If you don't want pickle, nor want to use an external library you can always do it the hard way:

import json

class NestEncoder(json.JSONEncoder):
    def default(self, obj):
        entry = dict(obj.__dict__)
        entry['__class__'] = obj.__class__.__name__
        return entry

class NestDecoder(json.JSONDecoder):
    def __init__(self):
        json.JSONDecoder.__init__(self, object_hook=self.dict_to_object)

    def dict_to_object(self, dictionary):
        if dictionary.get("__class__") == "Nested":
            obj = Nested.__new__(Nested)
        elif dictionary.get("__class__") == "Nest":
            obj = Nest.__new__(Nest)
        else:
            return dictionary

        for key, value in dictionary.items():
            if key != '__class__':
                setattr(obj, key, value)
        return obj

with open('nest.json', 'w') as file:
    json.dump(tree, file, cls=NestEncoder)

with open('nest.json', 'r') as file:
    tree2 = json.load(file, cls=NestDecoder)

print("Smoke test:")
print(tree[0].objects[0].name)
print(tree2[0].objects[0].name)

Assigning the the attributes to the classes doesn't have to be done dynamically with setattr() you can also do it manually.

There are probably plenty of pitfalls with doing it like this, so be careful.

André C. Andersen
  • 8,955
  • 3
  • 53
  • 79