gpt4 book ai didi

python - json.dump 不调用 default 或 cls

转载 作者:行者123 更新时间:2023-12-05 08:49:44 40 4
gpt4 key购买 nike

尝试将包含日期时间对象的字典序列化为 json 的键。其他一些答案建议使用 json.dump 参数 defaultcls 但是,这些方法似乎都没有被调用。请参阅下面的 MWE。我错过了什么?

使用默认

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)
Traceback (most recent call last):
File "test.py", line 21, in <module>
json.dump(test, fo, default=default)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 179, in dump
for chunk in iterable:
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 431, in _iterencode
yield from _iterencode_dict(o, _current_indent_level)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 376, in _iterencode_dict
raise TypeError(f'keys must be str, int, float, bool or None, '
TypeError: keys must be str, int, float, bool or None, not datetime

使用cls

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)
Traceback (most recent call last):
File "test.py", line 16, in <module>
json.dump(test, fo, cls=DateEncoder)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 179, in dump
for chunk in iterable:
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 431, in _iterencode
yield from _iterencode_dict(o, _current_indent_level)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 376, in _iterencode_dict
raise TypeError(f'keys must be str, int, float, bool or None, '
TypeError: keys must be str, int, float, bool or None, not datetime

最佳答案

TLDR:.default 仅针对 dict 值而不是键调用。

详细说明 Abhishek Kumars 的回答;在查看了 json.JSONEncoder 源代码后,.default 仅在不可序列化的 dict 值上调用,从不调用键。键必须是 strintfloatboolNone 之一。

要使用datetime对象作为键,必须覆盖.iterencode以使用递归预处理器方法将datetime转换为海峡:

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.JSONEncoder 更新为在键和值上使用默认设置会很好 - 创建于:https://bugs.python.org/issue41569 的问题

关于python - json.dump 不调用 default 或 cls,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63393059/

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