我想要
json.dump()
一个具有 datetime.date
类型键的字典,为此,我创建了一个序列化器类,将 date
键编码为字符串。令我惊讶的是,它与 json.dumps()
一起工作,但与 json.dump()
一起抛出错误。最后,我能够使用解决方法进行转储,但我想了解这里发生的情况:为什么序列化器类可以与 json.dumps()
一起使用,而不能与 json.dump()
一起使用?
我尝试编写一个类似的函数来与
default=
而不是 cls=
一起使用,尝试来回重写,尝试改编我在网络上找到的一些示例,但我总是遇到相同的错误。即使在阅读了文档之后,我也不知道我在这里缺少什么。请告诉我我需要在这里更改什么才能序列化日期并转储字典。
这是 MRE(Python 3.8.6):
import json
import datetime
class JSONSerializer(json.JSONEncoder):
@staticmethod
def convert_if_date(_date):
if isinstance(_date, datetime.date):
return _date.strftime('%Y-%m-%d')
return _date
def date_insensitive_encode(self, obj):
if isinstance(obj, dict):
return {self.convert_if_date(k): v for k, v in obj.items()}
return obj
def encode(self, obj):
return super(JSONSerializer, self).encode(
self.date_insensitive_encode(obj))
test_dict = {datetime.date(2022, 7, 10): 'OK'}
print(json.dumps(test_dict, cls=JSONSerializer))
# this prints: {"2022-07-11": "OK"}
with open('dump.json', 'w') as w:
json.dump(test_dict, w, cls=JSONSerializer)
# but this throws a TypeError
完整错误:
Traceback (most recent call last):
File "E:/Progz/Python/AppKH/datacontrol/so_mre.py", line 28, in <module>
json.dump(test_dict, w, cls=JSONSerializer)
File "C:\Program Files\Python38\lib\json\__init__.py", line 179, in dump
for chunk in iterable:
File "C:\Program Files\Python38\lib\json\encoder.py", line 431, in _iterencode
yield from _iterencode_dict(o, _current_indent_level)
File "C:\Program Files\Python38\lib\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 date
从以前的经验来看,我认为基类
encode()
的json.JSONEncoder
方法仅在调用dumps()
方法时使用,而不是在dump()
调用时使用,但显然事实并非如此。 (所以我之前的解决方案不适用)......但好消息是我能够做我认为你想做的事情,只需以一种不同的、更简单的方式,同时使用这两种方法 - 并且只需要覆盖 encode()
方法这样做。from collections.abc import MutableMapping
import json
import datetime
class JSONSerializer(json.JSONEncoder):
def encode(self, obj):
# Convert dictionary keys that are datatime.dates into strings.
if isinstance(obj, MutableMapping):
for key in list(obj.keys()):
if isinstance(key, datetime.date):
strkey = key.strftime('%Y-%m-%d')
obj[strkey] = obj.pop(key)
return super().encode(obj)
test_dict = {datetime.date(2022, 7, 10): 'OK'}
print(json.dumps(test_dict, cls=JSONSerializer)) # -> {"2022-07-11": "OK"}
with open('dump.json', 'w') as w:
json.dump(test_dict, w, cls=JSONSerializer) # # Works now, too.
from collections.abc import MutableMapping
import json
import numpy as np
class JSONSerializer(json.JSONEncoder):
def encode(self, obj):
# Convert dictionary keys that are tuples into strings.
if isinstance(obj, MutableMapping):
for key in list(obj.keys()):
if isinstance(key, tuple):
strkey = "%d:%d" % key
obj[strkey] = obj.pop(key)
return super().encode(obj)
class Agent(object):
def __init__(self, states, alpha=0.15, random_factor=0.2):
self.state_history = [((0, 0), 0)] # state, reward
self.alpha = alpha
self.random_factor = random_factor
# start the rewards table
self.G = {}
self.init_reward(states)
def init_reward(self, states):
for i, row in enumerate(states):
for j, col in enumerate(row):
self.G[(j,i)] = np.random.uniform(high=1.0, low=0.1)
def memorize(self):
with open("memory.json", "w") as w:
json.dump(self.G, w, cls=JSONSerializer)
if __name__ == "__main__":
robot = Agent(states=np.zeros((6, 6)), alpha=0.1, random_factor=0.25)
print(robot.G)
robot.memorize()
在测试字符串编码时,它似乎返回了我所期望的内容,但是当调用 json.dump 发生时,自定义编码器似乎根本没有被调用。你知道为什么吗?
谢谢