gpt4 book ai didi

python - 为什么 JSONEncoder 不适用于命名元组?

转载 作者:太空宇宙 更新时间:2023-11-04 00:33:08 26 4
gpt4 key购买 nike

我无法将 collections.namedtuple 转储为正确的 JSON。

首先,考虑 official使用自定义 JSON 序列化程序的示例:

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 如何对 Friend 对象进行 JSON 化:

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 是预定义的命名元组

最佳答案

正如我在评论中所说,json.JSONEncoder 仅在遇到它不知道如何序列化自身的对象类型时才调用 default。有一个 table of themjson 文档中。这是它的屏幕截图,以供引用:

table of types supported by default

请注意 tuple 在列表中,并且由于 namedtupletuple 的子类,它也适用于它们。 (即因为 isinstance(friend_instance, tuple)True)。

这就是为什么您处理 Friend 类实例的代码永远不会被调用的原因。

下面是一个解决方法——即创建一个简单的 Wrapper 类,其实例不会json.JSONEncoder 认为的类型它已经知道如何处理,然后指定一个 default= 关键字参数函数,每当遇到它不知道如何处理的对象时都会调用该函数。

我的意思是:

import json
from collections import namedtuple

class Wrapper(object):
""" Container class for objects with an _asdict() method. """
def __init__(self, obj):
assert hasattr(obj, '_asdict'), 'Cannot wrap object with no _asdict method'
self.obj = obj


if __name__ == '__main__':

Friend = namedtuple("Friend", ["id", 'f_name', 'l_name'])
t = Friend(21, 'Steve', 'Rogerson')
print(t)
print(json.dumps(t))
print(json.dumps(Wrapper(t), default=lambda wrapped: wrapped.obj._asdict()))

输出:

Friend(id=21, f_name='Steve', l_name='Rogerson')
[21, "Steve", "Rogerson"]
{"id": 21, "f_name": "Steve", "l_name": "Rogerson"}

有关其他信息和见解,另请查看 my answer相关问题Making object JSON serializable with regular encoder .

关于python - 为什么 JSONEncoder 不适用于命名元组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45128211/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com