JSON 序列化器类 - 为什么 json.dumps() 有效,而 json.dump() 无效?

问题描述 投票:0回答:2

我想要

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
python json python-3.x serialization
2个回答
2
投票

以前的经验来看,我认为基类

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.



0
投票

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 发生时,自定义编码器似乎根本没有被调用。你知道为什么吗?

谢谢

© www.soinside.com 2019 - 2024. All rights reserved.