【发布时间】:2017-07-16 11:49:04
【问题描述】:
我无法将 collections.namedtuple 转储为正确的 JSON。
首先,考虑使用自定义 JSON 序列化程序的 official 示例:
import json
class ComplexEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, complex):
return [obj.real, obj.imag]
# Let the base class default method raise the TypeError
return json.JSONEncoder.default(self, obj)
json.dumps(2 + 1j, cls=ComplexEncoder) # works great, without a doubt
第二个,现在考虑以下示例,它告诉 Python 如何 JSON 化 Friend 对象:
import json
class Friend():
""" struct-like, for storing state details of a friend """
def __init__(self, _id, f_name, l_name):
self._id = _id
self.f_name = f_name
self.l_name = l_name
t = Friend(21, 'Steve', 'Rogerson')
class FriendEncoder(json.JSONEncoder):
""" take a Friend object and make it truly json """
def default(self, aFriend):
if isinstance(aFriend, Friend):
return {
"id": aFriend._id,
"f_name": aFriend.f_name,
"l_name": aFriend.l_name,
}
return super(FriendEncoder, self).default(aFriend)
json.dumps(t, cls=FriendEncoder) # returns correctly JSONized string
最后当我们尝试使用 namedtuples 实现相同的东西时,json.dumps(t, cls=FriendEncoder) 没有给出任何错误但给出了错误的输出。看看:
import pdb
import json
from collections import namedtuple
Friend = namedtuple("Friend", ["id", 'f_name', 'l_name'])
t = Friend(21, 'Steve', 'Rogerson')
print(t)
class FriendEncoder(json.JSONEncoder):
""" take a Friend collections.namedtuple object and make it truly json """
def default(self, obj):
if True: # if isinstance(obj, Friend):
ans = dict(obj._asdict())
pdb.set_trace() # WOW!! even after commenting out the if and hardcoding True, debugger doesn't get called
return ans
return json.JSONEncoder.default(self, obj)
json.dumps(t, cls=FriendEncoder)
我得到的输出不是字典,而只是一个值列表,即[21, 'Steve', 'Rogerson']
为什么?
默认行为是否会导致信息丢失?
json.dumps 会忽略显式传递的编码器吗?
编辑: 通过正确的 jsonized namedtuple 我的意思是 json.dumps 应该返回类似 exactly dict(nt._asdict()) 的数据,其中 nt 是一个预定义的 namedtuple
【问题讨论】:
-
default方法不会被tuple、list等的子类调用。 -
@vaultah 我同意
default方法没有被调用。但是你能证实“tuple、list等的子类” -
json.JSONEncoder仅在它不知道如何序列化自身的对象上调用default (),其中包括tuples、lists 和dicts(以及它们的子类) )。这意味着为了做你想做的事,你需要“欺骗”它。 -
请描述你认为/想要一个已经“真正”转换为 JSON 的
namedtuple会是什么样子,因为这样的东西不是定义的 JSON object 另外,你如何期望它如果它是非标准的,以后再解码? -
"
json.JSONEncoder只调用default ()对它还不知道如何序列化自身的对象,其中包括tuples、lists和 ..." 我无法理解底层源码(json/encoder.py)能解释一下吗?
标签: python json data-structures