覆盖继承的默认支持对象(如dict,list)的嵌套JSON编码 [英] Overriding nested JSON encoding of inherited default supported objects like dict, list

查看:171
本文介绍了覆盖继承的默认支持对象(如dict,list)的嵌套JSON编码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经设置了一些我们自己的类,它们是从字典进行子类化的。然而,当我想将它们编码为JSON(使用Python)时,我希望它们被序列化,我可以将它们解码成原始对象而不是一个dict。



所以我想支持我自己的类的嵌套对象(从dict继承)。



  class ShadingInfoEncoder(json.JSONEncoder):
def encode(self,o):
如果键入(o).__ name__ ==NodeInfo:
return'{_NodeInfo:'+ super(ShadingInfoEncoder,self).encode(o)+'}'
elif type(o) ==ShapeInfo:
return'{_ShapeInfo:'+ super(ShadingInfoEncoder,self).encode(o)+'}'
elif type(o).__ name__ ==ShaderInfo :
return'{_ShaderInfo:'+ super(ShadingInfoEncoder,self).encode(o)+'}'

return super(ShadingInfoEncoder,self).encode(o)

And:

 $ $ $ $ $ $ $ $ $ $ $ $ 
如果isinstance(o,NodeInfo):
返回'{_NodeInfo: '+ super(ShadingInfoEncoder,self).encode(o)+'}'
elif isinstance(o,ShapeInfo):
return'{_ShapeInfo:'+ super(ShadingInfoEncoder,self) (o)+'}'
elif isinstance(o,ShaderInfo):
return'{_ShaderInfo:'+ super(ShadingInfoEncoder,self).encode(o)+'}'

return super(ShadingInfoEncoder,self).encode(o)

,而不是当它们被嵌套或者被转储的第一个对象不是这些类型时。因此,这仅在输入对象为该类型时才起作用。但是不是当它嵌套时。



我不知道如何递归编码这个JSON,所以所有的嵌套/包含的实例都是按照相同的规则编码的。我认为使用JSONEncoder的默认方法会更容易(因为每当一个对象是不受支持的类型时调用它)。然而,由于我的对象是继承自dict的,所以它们被解析了

解决方案

我结束了以下操作。

  class ShadingInfoEncoder(json.JSONEncoder):
def _iterencode(self,o,markers = None):
jsonPlaceholderNames = (_ShaderInfo,ShaderInfo),
(_ShapeInfo,ShapeInfo),
(_NodeInfo,NodeInfo))
for jsonPlaceholderName,cls in customIterEncode:
if isinstance o,cls):
yield'{'+ jsonPla ceholderName +':'
为超级块(ShadingInfoEncoder,self)._ iterencode(o,markers):
yield chunk
yield'}'
break
else :
为超级块(ShadingInfoEncoder,self)._ iterencode(o,markers):
yield chunk

我认为这不是最好的方法,但我在这里分享,看看有没有人可以告诉我我做错了什么,并告诉我最好的方法来做到这一点!



注意,我使用嵌套元组而不是字典,因为我想保留列出的顺序,所以我可以 - 在这个例子中,覆盖ShaderInfo成为_NodeInfo if ShaderInfo是从NodeInfo继承的对象。



我的解码器设置为按照(简化和部分代码)的方式执行某些操作:

 类ShadingInfoDecoder(json.JSONDecoder):
def解码(self,obj):
obj = super(ShadingInfoDecoder,self).decode(s)
如果isinstance(obj,dict):
解码器= [(_set,self。 setDecode),
(_NodeInfo,self.nodeInfoDecode),
(_ShapeInfo,self.shapeInfoDecode),
(_ShaderInfo,self.shaderInfoDecode)]

如果占位符在obj中:
return decoder(obj [placeholder])
else:
for obj中的k:
obj [k] = self.recursiveDecode(obj [k])
elif isinstance(obj,list):
for x in range(len(obj)):
obj [x] = self.recursiveDecode obj [x])

return obj

def setDecode(self,v):
return set(v)

def nodeInfoDecode (self,v):
o = NodeInfo()
o.update(self .recursiveDecode(v))
return o

def shapeInfoDecode(self,v):
o = ShapeInfo()
o.update(self.recursiveDecode(v) )
return o

def shaderInfoDecode(self,v):
o = ShaderInfo()
o.update(self.recursiveDecode(v))
return o

nodeInfoDecode方法获取输入的字典,并使用它来初始化NodeInfo的值/属性



更多信息:



另请参见我的关于如何更改序列化python对象的json编码行为的答案?


I've set up some classes of my own that are subclassed from a dictionary to act like them. Yet when I want to encode them to JSON (using Python) I want them to be serialized in a way that I can decode them back to the original objects instead of to a dict.

So I want to support nested objects of my own classes (that are inherited from dict).

I had tried stuff like:

class ShadingInfoEncoder(json.JSONEncoder):
    def encode(self, o):
        if type(o).__name__ == "NodeInfo":
            return '{"_NodeInfo": ' + super(ShadingInfoEncoder, self).encode(o) + '}'
        elif type(o).__name__ == "ShapeInfo":
            return '{"_ShapeInfo": ' + super(ShadingInfoEncoder, self).encode(o) + '}'
        elif type(o).__name__ == "ShaderInfo":
            return '{"_ShaderInfo": ' + super(ShadingInfoEncoder, self).encode(o) + '}'

        return super(ShadingInfoEncoder, self).encode(o)

And:

class ShadingInfoEncoder(json.JSONEncoder):
    def encode(self, o):
        if isinstance(o, NodeInfo):
            return '{"_NodeInfo": ' + super(ShadingInfoEncoder, self).encode(o) + '}'
        elif isinstance(o, ShapeInfo):
            return '{"_ShapeInfo": ' + super(ShadingInfoEncoder, self).encode(o) + '}'
        elif isinstance(o, ShaderInfo):
            return '{"_ShaderInfo": ' + super(ShadingInfoEncoder, self).encode(o) + '}'

        return super(ShadingInfoEncoder, self).encode(o)

It works in general, yet not when they are nested or the first object getting dumped is not of those types. Thus this only works when the input object is of that type. Yet not when it's nested.

I'm not sure how to encode this JSON recursively so all nested/contained instances are encoded according to the same rules.

I thought it would be easier to the use the JSONEncoder's default method (as that gets called whenever an object is of an unsupported type.) Yet since my objects are inherited from dict they get parsed to dictionaries instead of being process by the 'default' method.

解决方案

I ended up doing the following.

class ShadingInfoEncoder(json.JSONEncoder):
    def _iterencode(self, o, markers=None):
        jsonPlaceholderNames = (("_ShaderInfo", ShaderInfo),
                            ("_ShapeInfo", ShapeInfo),
                            ("_NodeInfo", NodeInfo))
        for jsonPlaceholderName, cls in customIterEncode:
            if isinstance(o, cls):
                yield '{"' + jsonPlaceholderName+ '": '
                for chunk in super(ShadingInfoEncoder, self)._iterencode(o, markers):
                    yield chunk
                yield '}'
                break
        else:
            for chunk in super(ShadingInfoEncoder, self)._iterencode(o, markers):
                yield chunk

I assume this is not the best way to do this, yet I'm sharing it here to see if anyone else can tell me what I'm doing wrong and show me the best way to do this!

Note that I'm using nested tuples instead of a dictionary because I wanted to keep the order they were listed so I could - in this example - override ShaderInfo becoming _NodeInfo if ShaderInfo was an object that inherited from NodeInfo.

My decoder is set up to do something along the lines of (simplified and part of code):

class ShadingInfoDecoder(json.JSONDecoder):
    def decode(self, obj):
        obj = super(ShadingInfoDecoder,self).decode(s)
        if isinstance(obj, dict):
            decoders = [("_set",self.setDecode),
                        ("_NodeInfo", self.nodeInfoDecode),
                        ("_ShapeInfo", self.shapeInfoDecode),
                        ("_ShaderInfo", self.shaderInfoDecode)]
            for placeholder, decoder in decoders:
                if placeholder in obj:
                    return decoder(obj[placeholder])
                else:
                    for k in obj:
                        obj[k] = self.recursiveDecode(obj[k])
        elif isinstance(obj, list):
            for x in range(len(obj)):
                obj[x] = self.recursiveDecode(obj[x])

        return obj

    def setDecode(self, v):
        return set(v)

    def nodeInfoDecode(self, v):
        o = NodeInfo()
        o.update(self.recursiveDecode(v))
        return o

    def shapeInfoDecode(self, v):
        o = ShapeInfo()
        o.update(self.recursiveDecode(v))
        return o

    def shaderInfoDecode(self, v):
        o = ShaderInfo()
        o.update(self.recursiveDecode(v))
        return o

The nodeInfoDecode methods gets the entered dictionary and uses it to initialize the values/attributes of the NodeInfo object that gets created and returned.

More info:

Also see my answer on How to change json encoding behaviour for serializable python object?

这篇关于覆盖继承的默认支持对象(如dict,list)的嵌套JSON编码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆