Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么';JsoneCoder是否为namedtuples工作?_Python_Json_Data Structures - Fatal编程技术网

Python 为什么';JsoneCoder是否为namedtuples工作?

Python 为什么';JsoneCoder是否为namedtuples工作?,python,json,data-structures,Python,Json,Data Structures,我无法将集合转储为正确的JSON 第一< /强>,考虑使用自定义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 ra

我无法将
集合转储为正确的JSON

<强>第一< /强>,考虑使用自定义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如何使<代码>朋友< /Cord>对象:< /P>

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)
我得到的输出与dict不同,只是一个值列表,即
[21,'Steve','Rogerson']

为什么? 默认行为是否导致信息丢失?
json.dumps是否忽略显式传递的编码器



编辑:通过正确的jsonized namedtuple,我的意思是json.dumps应该返回与
dict(nt.\u asdict())
完全相同的数据,其中
nt
是一个预定义的namedtuple

,正如我在评论中所说,
json.jsonecoder
仅在遇到不知道如何序列化自身的对象类型时调用
default
json
文档中有一个。以下是它的屏幕截图,以便于参考:

请注意,
tuple
在列表中,由于
namedtuple
tuple
的子类,因此它也适用于它们。(即,因为
isinstance(友元实例,元组)
→ <代码>真

这就是为什么处理
Friend
类实例的代码从未被调用。


下面是一个解决方法-即创建一个简单的
包装器
类,其实例不会是
json.jsonecoder
认为它已经知道如何处理的类型,然后指定一个
default=
keyword参数函数,每当遇到一个它还不知道如何处理的对象时,都要调用该函数

我的意思是:

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 wrapper: wrapper.obj._asdict()))
输出:

Friend(id=21,f_name='Steve',l_name='Rogerson')
[21,“史蒂夫”,“罗杰森”]
{“id”:21,“f_name”:“Steve”,“l_name”:“Rogerson”}

有关其他信息和见解,请查看相关问题。

对于
元组
列表
等的子类,不会调用
默认
方法。@vaultah我同意不会调用
默认
方法。但是你能证实“对于
tuple
list
等的子类,
json.jsonecoder
只调用
default()
对象,它还不知道如何序列化它自己,包括
tuple
s、
list
s和
dict
s(以及它们的子类)。这意味着为了做你想做的事情,你需要“欺骗”它。请描述你认为/想要一个已经“真正”转换为JSON的
namedtuple
会是什么样子,因为这样的东西也不是一个定义的东西,如果它是非标准的,你希望它以后如何被解码?“
json.jsonecoder
只对对象调用
default()
,它还不知道如何序列化自身,其中包括
元组
列表
和…”我无法理解底层源代码(
json/encoder.py
)你能解释一下吗?我正在寻找类似问题的解决方案。非常感谢。