JSON序列化自定义非序列化对象的常规方法是将json.JSONEncoder
子类化,然后将自定义编码器传递给转储。
通常是这样的:
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, foo):
return obj.to_json()
return json.JSONEncoder.default(self, obj)
print json.dumps(obj, cls = CustomEncoder)
我想做的是用默认的编码器使一些东西序列化。我环顾四周,什么也找不到。
我的想法是,编码器会查看某个字段来确定json编码。类似于__str__
的东西。可能是一个__json__
字段。
在python中有类似的东西吗?
我想让一个模块的一个类成为JSON可序列化的,每个使用这个包的人都不用担心实现自己的自定义编码器。
我建议在类定义中加入hack。这样,一旦定义了类,它就支持JSON。示例:
您可以像这样扩展dict类:
现在要使用常规编码器使类可序列化,请扩展“serializable”:
print(obj)
将打印如下内容:print(json.dumps(obj, indent=4))
将打印如下内容:正如我在对您的问题的评论中所说,在查看了
json
模块的源代码之后,它似乎不适合做您想要的事情。然而,这个目标可以通过所谓的monkey-patching来实现 (见问题What is a monkey patch?)。 这可以在包的__init__.py
初始化脚本中完成,并且会影响所有后续的json
模块序列化,因为模块通常只加载一次,结果缓存在sys.modules
中。修补程序将默认json编码器的
default
方法更改为默认的default()
。为了简单起见,下面是一个作为独立模块实现的示例:
模块:
make_json_serializable.py
使用它很简单,因为补丁是通过简单地导入模块来应用的。
示例客户端脚本:
要保留对象类型信息,特殊方法还可以将其包含在返回的字符串中:
它生成以下JSON,现在包含类名:
马奇克躺在这里
甚至比让替换的
default()
寻找一个特别命名的方法更好的是,它能够自动序列化大多数Python对象,包括用户定义的类实例,而不需要添加特殊的方法。在研究了许多替代方案之后,以下使用pickle
模块的方案似乎最接近我的理想:模块:
make_json_serializable2.py
当然,举例来说,不能对所有扩展类型进行pickle。不过,有一些方法是通过pickle协议定义的,它们通过编写与您之前所建议的类似的特殊方法来处理这些问题,但对于数量少得多的情况,这样做可能是必要的。
不管怎样,使用pickle协议还意味着,通过对任何使用传入字典中的任何
'_python_object'
键的调用提供自定义的object_hook
函数参数,只要有一个键,就可以相当容易地重构原始Python对象。类似于:如果必须在许多地方执行此操作,则可能需要定义一个自动提供额外关键字参数的包装函数:
当然,这也可以通过monkey将其修补到
json
模块中,使函数成为默认的object_hook
(而不是None
)。我的想法是使用
pickle
从answerby Raymond Hettinger到另一个JSON序列化问题,我认为这个问题非常可信,而且是一个官方源代码(在Python核心开发人员中也是如此)。移植到Python 3
上面的代码不能像Python 3中所示工作,因为
json.dumps()
返回了bytes
对象,而JSONEncoder
无法处理该对象。然而,这种方法仍然有效。解决此问题的一个简单方法是latin1
“解码”从pickle.dumps()
返回的值,然后从latin1
对其进行“编码”,然后再将其传递到as_python_object()
函数中的pickle.loads()
。这是因为任意二进制字符串都是有效的latin1
,它们总是可以被解码为Unicode,然后再次编码回原始字符串(如Sven Marnach在this answer中指出的那样)。(尽管下面的代码在Python 2中运行良好,但是
latin1
解码和编码是多余的。)相关问题 更多 >
编程相关推荐