很容易更改不是JSON可序列化对象的格式,例如datetime.datetime。
出于调试目的,我的要求是改变一些自定义对象从基对象(如dict
和list
)扩展的方式,以json格式序列化。代码:
import datetime
import json
def json_debug_handler(obj):
print("object received:")
print type(obj)
print("\n\n")
if isinstance(obj, datetime.datetime):
return obj.isoformat()
elif isinstance(obj,mDict):
return {'orig':obj , 'attrs': vars(obj)}
elif isinstance(obj,mList):
return {'orig':obj, 'attrs': vars(obj)}
else:
return None
class mDict(dict):
pass
class mList(list):
pass
def test_debug_json():
games = mList(['mario','contra','tetris'])
games.src = 'console'
scores = mDict({'dp':10,'pk':45})
scores.processed = "unprocessed"
test_json = { 'games' : games , 'scores' : scores , 'date': datetime.datetime.now() }
print(json.dumps(test_json,default=json_debug_handler))
if __name__ == '__main__':
test_debug_json()
输出:
{"date": "2013-05-07T01:03:13.098727", "games": ["mario", "contra", "tetris"], "scores": {"pk": 45, "dp": 10}}
期望输出:
{"date": "2013-05-07T01:03:13.098727", "games": { "orig": ["mario", "contra", "tetris"] ,"attrs" : { "src":"console"}} , "scores": { "orig": {"pk": 45, "dp": 10},"attrs":
"processed":"unprocessed }}
default
处理程序不适用于可序列化对象吗?
如果没有,我如何重写它,而不向扩展类添加json方法?
另外,还有这个版本的JSON编码器不工作:
class JsonDebugEncoder(json.JSONEncoder):
def default(self,obj):
if isinstance(obj, datetime.datetime):
return obj.isoformat()
elif isinstance(obj,mDict):
return {'orig':obj , 'attrs': vars(obj)}
elif isinstance(obj,mList):
return {'orig':obj, 'attrs': vars(obj)}
else:
return json.JSONEncoder.default(self, obj)
如果有一个黑客使用pickle,__getstate__,__setstate__,
,然后在pickle.loads对象上使用json.dumps,我也会打开它,我试过了,但是没有成功。
FastTurtle的答案可能是一个更干净的解决方案。
根据我在问答中解释的技巧,这里有一些接近你想要的东西:Overriding nested JSON encoding of inherited default supported objects like dict, list
这将导致:
这样您就可以对其进行编码并将其解码回它来自的python对象。
编辑:
这里有一个版本,它实际上编码到你想要的输出,也可以解码它。每当字典包含“orig”和“attr”时,它将检查“orig”是否包含字典或列表,如果包含,则它将分别将对象转换回mdct或mList。
以下是有关输出的更多信息:
很抱歉有任何不好的命名约定,这是一个快速设置。;)
注意:日期时间不会被解码回python表示。可以通过检查任何名为“date”且包含日期时间的有效字符串表示形式的dict键来实现。
似乎要实现您想要的行为,在给定的限制下,您必须深入研究
JSONEncoder
类。下面我写了一个定制的JSONEncoder
,它重写iterencode
方法,将定制的isinstance
方法传递给_make_iterencode
。它不是世界上最干净的东西,但似乎是最好的选择,它保持定制到最低限度。现在可以对
CustomObjectEncoder
进行子类化,以便它正确地序列化您的自定义对象。CustomObjectEncoder
也可以做一些很酷的事情,比如处理嵌套对象。正如其他人已经指出的那样,默认处理程序只对不属于已识别类型的值进行调用。我建议的解决方案是预处理要序列化的对象,在列表、元组和字典上递归,但在自定义类中包装其他值。
像这样的:
在将对象传递到json.dumps之前,您可以调用此函数,如下所示:
请注意,此代码正在检查类与列表、元组或字典完全匹配的对象,因此从这些类型扩展的任何自定义对象都将被包装而不是解析。因此,常规列表、元组和字典将像往常一样序列化,但所有其他值都将传递给默认处理程序。
所有这些操作的最终结果是,确保每个到达默认处理程序的值都包装在这些调试类中的一个中。因此,首先要做的是提取原始对象,如下所示:
然后可以检查原始对象的类型,并处理需要特殊处理的类型。对于其他一切,您应该只返回原始对象(因此处理程序的最后一个返回应该是
return obj
,而不是return None
)。请注意,此代码不会检查不可序列化的值。这些将通过最后的
return obj
,然后将被序列化程序拒绝,并再次传递回默认处理程序-只是这次没有调试包装器。如果需要处理该场景,可以在处理程序的顶部添加一个检查,如下所示:
视频演示:http://ideone.com/tOloNq
相关问题 更多 >
编程相关推荐