自定义 json 编码器未被调用

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

我尝试将 这篇文章 中的 martineau 解决方案应用于稍微不同的情况,但似乎由于某些模糊的(至少对我来说)原因,自定义编码器不是从 json.dump() 方法调用的。

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

谢谢

python json
1个回答
0
投票

这可能应该被认为是

json
包的实现细节,也可能是 Python 版本的东西。无论如何,这对您的实施至关重要:

  • dump()
    函数在内部调用编码器上的
    iterencode()
    方法(请参阅实际源代码中的第169行和第176行
  • 然而,
    dumps()
    函数在内部调用
    encode()
    (参见第231行和第238行)。

您可以通过覆盖

iterencode()
中的
JSONSerializer
来验证这一点,如下所示:

class JSONSerializer(json.JSONEncoder):
    ...
    def iterencode(self, *args, **kwargs):
        print("iterencode called")
        return super().iterencode(*args, **kwargs)

...您将看到“iterencode called”将与您的测试代码一起打印。

您在问题中链接的另一个 Stack Overflow 问题似乎也有同样的问题,至少在使用较新版本的 Python 时(我目前正在使用 3.11 来写这篇文章)。

我有两个解决方案:

  1. 要么在您的
    dumps()
    方法中使用
    Agent.memorize()
    ,例如像这样:
    def memorize(self):
        with open("memory.json", "w") as w:
            w.write(json.dumps(self.G, cls=JSONSerializer))
    
  2. 或者提供您自己的
    iterencode()
    实现。
© www.soinside.com 2019 - 2024. All rights reserved.