Python json.dump不调用default或cls
尝试序列化包含datetime对象作为json键的dict。其他一些答案建议使用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
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)