Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.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 json.dump不调用default或cls_Python_Json_Python 3.x_Datetime - Fatal编程技术网

Python json.dump不调用default或cls

Python json.dump不调用default或cls,python,json,python-3.x,datetime,Python,Json,Python 3.x,Datetime,尝试序列化包含datetime对象作为json键的dict。其他一些答案建议使用json.dump参数default或cls但是,这两种方法似乎都没有被调用。见下文MWEs。我错过了什么 使用默认值 from datetime import datetime import json def default(obj): print("Default Called") if isinstance(obj, (datetime, date)): r

尝试序列化包含datetime对象作为json键的dict。其他一些答案建议使用
json.dump
参数
default
cls
但是,这两种方法似乎都没有被调用。见下文MWEs。我错过了什么

使用
默认值

from datetime import datetime
import json

def default(obj):
    print("Default Called")
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()

test = {datetime(1970, 1, 1, 8, 0, 0): 10}

with open("output.json", "w") as fo:
    json.dump(test, fo, default=default)
from datetime import datetime
import json

class DateEncoder(json.JSONEncoder):
    def default(self, obj):
        print("Default called")
        if isinstance(obj, (datetime, date)):
            return obj.isoformat()

        # Let the base class default method raise the TypeError
        return json.JSONEncoder.default(self, obj)

test = {datetime(1970, 1, 1, 8, 0, 0): 10}

with open("output.json", "w") as fo:
    json.dump(test, fo, cls=DateEncoder)
回溯(最近一次呼叫最后一次):
文件“test.py”,第16行,在
dump(test、fo、cls=DateEncoder)
文件“/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/_init__.py”,第179行,在转储文件中
对于iterable中的块:
文件“/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py”,第431行,在iterencode中
从(o)(当前)(缩进)级别)得到的收益
文件“/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py”,第376行,在
raise TypeError(f'键必须是str、int、float、bool或None,'
TypeError:键必须是str、int、float、bool或None,而不是datetime
您可以尝试以下方法:

class DatesToStrings(json.JSONEncoder):
    def _encode(self, obj):
        if isinstance(obj, dict):
            def transform_date(o):
                return self._encode(o.isoformat() if isinstance(o, datetime) else o)
            return {transform_date(k): transform_date(v) for k, v in obj.items()}
        else:
            return obj

    def encode(self, obj):
        return super(DatesToStrings, self).encode(self._encode(obj))

TLDR:
.default
仅为
dict
值而不是键调用

详细说明阿披舍克·库马尔的答案;在查看了
json.jsonecoder
源代码之后,
默认值仅在
dict
值上调用,这些值不可序列化,从不使用键。键必须是
str
int
float
bool
None
中的一个

要使用
datetime
对象作为键,必须覆盖
.iterencode
,才能使用递归预处理器方法将
datetime
转换为
str

test = {
        "key_1": "Value_1",
        "key_2": 10,
        "key_3": ["list_" + str(i) for i in range(5)],
        "key_4": {"nestkey_" + str(i) : "nestvalue_" + str(i) for i in range(5) },
        "key_5": datetime.datetime(1970, 1, 1, 8, 0, 0),
        datetime.datetime(1970, 1, 1, 8, 0, 0): "datetime_key"
}

class DateTimeEncoder(json.JSONEncoder):

    def _preprocess_date(self, obj):
        if isinstance(obj, (datetime.date, datetime.datetime, datetime.timedelta)):
            return str(obj)
        elif isinstance(obj, dict):
            return {self._preprocess_date(k): self._preprocess_date(v) for k,v in obj.items()}
        elif isinstance(obj, list):
            return [self._preprocess_date(i) for i in obj]
        return obj

    def default(self, obj):
        if isinstance(obj, (datetime.date, datetime.datetime, datetime.timedelta)):
            return str(obj)
        return super().default(obj)

    def iterencode(self, obj):
        return super().iterencode(self._preprocess_date(obj))

with open('output.json', 'w') as fo:
    json.dump(test, fo, cls=DateTimeEncoder)

对于较大的字典来说,这显然是一个昂贵的操作,因此需要谨慎。另外,更新
json.jsonecoder
以使用默认键和值也很好-问题创建于:

datetime对象是不可变的,感谢Abhishek,但不幸的是它仍然返回
TypeError:Object of类型集不是JSON可序列化的
您是否尝试过以下操作:
将open(“out.JSON”,“w”)作为fo:JSON.dump(JSON.dumps(test,cls=DatesToStrings),fo)
是的,我尝试过两个版本。您能告诉我如何定义
test
吗?我刚刚复制了您的测试:
test={datetime(1970,1,1,8,0,0):10}
在我这边发现了一种字体。是的,这很有效。谢谢。知道我原来的帖子为什么不起作用吗?
class DatesToStrings(json.JSONEncoder):
    def _encode(self, obj):
        if isinstance(obj, dict):
            def transform_date(o):
                return self._encode(o.isoformat() if isinstance(o, datetime) else o)
            return {transform_date(k): transform_date(v) for k, v in obj.items()}
        else:
            return obj

    def encode(self, obj):
        return super(DatesToStrings, self).encode(self._encode(obj))
with open("output.json", "w") as fo:
    json.dump( json.dumps( test, cls=DatesToStrings), fo, cls=DatesToStrings)

test = {
        "key_1": "Value_1",
        "key_2": 10,
        "key_3": ["list_" + str(i) for i in range(5)],
        "key_4": {"nestkey_" + str(i) : "nestvalue_" + str(i) for i in range(5) },
        "key_5": datetime.datetime(1970, 1, 1, 8, 0, 0),
        datetime.datetime(1970, 1, 1, 8, 0, 0): "datetime_key"
}

class DateTimeEncoder(json.JSONEncoder):

    def _preprocess_date(self, obj):
        if isinstance(obj, (datetime.date, datetime.datetime, datetime.timedelta)):
            return str(obj)
        elif isinstance(obj, dict):
            return {self._preprocess_date(k): self._preprocess_date(v) for k,v in obj.items()}
        elif isinstance(obj, list):
            return [self._preprocess_date(i) for i in obj]
        return obj

    def default(self, obj):
        if isinstance(obj, (datetime.date, datetime.datetime, datetime.timedelta)):
            return str(obj)
        return super().default(obj)

    def iterencode(self, obj):
        return super().iterencode(self._preprocess_date(obj))

with open('output.json', 'w') as fo:
    json.dump(test, fo, cls=DateTimeEncoder)