2015-08-04 2 views
1

Я пытаюсь кодировать/декодировать вложенные объекты, и у меня есть список вложенных объектов как строка вместо объектов JSON.python custom JSON encoder/decoder не работает как ожидалось

class A: 
    def __init__ (self, n, a): 
     self.n = n 
     self.a = a 

class B: 
    def __init__ (self, b, listOfA): 
     self.b = b 
     self.listOfA = [] 
     for a in listOfA: 
      self.listOfA.append(a) 

class AEncoder: 
    def default (self, obj): 
     if isinstance (obj, A): 
      return { 
       'n' : obj.n 
       'a' : obj.a 
      } 
     return json.JSONEncoder.default(self, obj) 

class BEncoder: 
    def default (self, obj): 
     if isinstance (obj, B): 
      return { 
       'b' : obj.n 
       'listOfA' : json.dumps(obj.listOfA, cls=AEncoder) 
      } 
     return json.JSONEncoder.default(self, obj) 

listOfA = [A('n1', 'a1'), A('n2', 'a2')] 
tmpB = B('b', listOfA) 

Для объекта A он работает правильно, так как он довольно прямолинейный. Выход для B я получаю примерно следующее:

{ 
    "b" : "b" 
    "listOfA" : "[{\"n\" : \"n1\", \"a\" : \"a1\"}, {\"n\" : \"n2\", \"a\" : \"a2\"}]" 
} 

Любые идеи, в которых я ошибаюсь? Вывод должен быть таким:

{ 
    "b" : "b" 
    "listOfA" : [{"n" : "n1", "a" : "a1"}, {"n" : "n2", "a" : "a2"}] 
} 

ответ

1

У вас было несколько опечаток в вашем коде, не хватает запятых в словарях, и вы обратитесь к obj.n, когда вы имели в виду obj.b в BEncoder.

Кроме того, проблема заключается в том, что вы используете json.dumps() в BEncoder. Этот метод возвращает правильно отформатированную строку json . Затем BEncoder видит эту строку и думает, что вы хотите, чтобы значение listOfA было строкой, которое затем должно быть правильно закодировано для json, таким образом, символ, который вы видите.

Это решение, которое вместо возвращения строки возвращает «сериализуемый объект» (например, список, dict и т. Д.), Если требуется кодер. Он строит список (который сериализуется) из словарей (serializable), возвращаемых AEncoder(). Default().

import json 
from json import JSONEncoder 

class A: 
    def __init__ (self, n, a): 
     self.n = n 
     self.a = a 

class B: 
    def __init__ (self, b, listOfA): 
     self.b = b 
     self.listOfA = [] 
     for a in listOfA: 
      self.listOfA.append(a) 

class AEncoder(JSONEncoder): 
    def default (self, obj): 
     if isinstance (obj, A): 
      return { 'n' : obj.n, 'a' : obj.a } 
     return json.JSONEncoder.default(self, obj) 

class BEncoder(JSONEncoder): 
    def default (self, obj): 
     if isinstance (obj, B): 
      a = AEncoder() 
      return { 'b' : obj.b, 'listOfA' : [a.default(x) for x in obj.listOfA] } 
     return json.JSONEncoder.default(self, obj) 

listOfA = [A('n1', 'a1'), A('n2', 'a2')] 
tmpB = B('b', listOfA) 
print(json.dumps(tmpB, cls=BEncoder)) 

Выход:

{"b": "b", "listOfA": [{"a": "a1", "n": "n1"}, {"a": "a2", "n": "n2"}]} 
+0

Awesome, работал как шарм! О опечатках я заметил их после того, как я опубликовал их, но их отстранили за звонок в conf ... Спасибо! – user3379755