Search code examples
pythonjsonpickle

Python: unable to print the same object twice or more using jsonpickle


In a fairly complex project I came up with this issue at some point, where nested objects should be printed and the same objects have to exist there twice or more. Here I provide a simplified version of the code to reproduce the issue:

import jsonpickle

class nickname:
    def __init__(self, name:str, id:int):
        self.name = name
        self.id = id


class test_class:
    def __init__(self, name:str, age:int, nicknames:[nickname]):
        self.name = name
        self.age = age
        self.nicknames = nicknames

nicknames = []
nicknames.append(nickname('Bomber', 1))
nicknames.append(nickname('Roccia', 2))

test_dict = {}
test_dict['key1'] = test_class('Gigi', 12, nicknames)
test_dict['key2'] = test_class('Sandro', 14, nicknames)

test_list = []
test_list.append(test_dict['key1'])
test_list.append(test_dict['key2'])
test_list.append(test_dict['key1'])

print(jsonpickle.encode(test_list, unpicklable=False))

This gives the output:

[{"name": "Gigi", "age": 12, "nicknames": [{"name": "Bomber", "id": 1}, {"name": "Roccia", "id": 2}]}, {"name": "Sandro", "age": 14, "nicknames": [null, null]}, null]

Where you can see that duplicate objects are null. Adding the make_refs=False param leads to:

[{"name": "Gigi", "age": 12, "nicknames": [{"name": "Bomber", "id": 1}, {"name": "Roccia", "id": 2}]}, {"name": "Sandro", "age": 14, "nicknames": "[<__main__.nickname object at 0x00BF50D0>, <__main__.nickname object at 0x00BF50F0>]"}, "<__main__.test_class object at 0x00BF5110>"]

Where object references are present, but still they are not encoded.

Does someone have a clue on how to resolve this issue? Of course I'd like duplicate objects to be reprinted instead of "null" fields.

Thanks


Solution

  • I believe json pickle doesn't support printing out duplicate objects. Instead it provides a reference to it. An alternative approach is to use json.dumps and have a lambda expression to recursively convert to dictionary.

    import json
    
    class nickname:
        def __init__(self, name:str, id:int):
            self.name = name
            self.id = id
    
    class person:
        def __init__(self, name:str, age:int, nicknames:[nickname]):
            self.name = name
            self.age = age
            self.nicknames = nicknames
    
    nicknames = [nickname('Bomber', 1), nickname('Roccia', 2)]
    test_list = [person('Gigi', 12, nicknames), person('Sandro', 14, nicknames)]
    results = json.dumps(test_list, default=lambda x: x.__dict__)
    print(results)
    

    This outputs:

    [{"name": "Gigi", "age": 12, "nicknames": [{"name": "Bomber", "id": 1}, {"name": "Roccia", "id": 2}]}, {"name": "Sandro", "age": 14, "nicknames": [{"name": "Bomber", "id": 1}, {"name": "Roccia", "id": 2}]}]