我尝试将 这篇文章 中的 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 发生时,自定义编码器似乎根本没有被调用。你知道为什么吗?
谢谢
这可能应该被认为是
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 来写这篇文章)。
我有两个解决方案:
dumps()
方法中使用Agent.memorize()
,例如像这样:
def memorize(self):
with open("memory.json", "w") as w:
w.write(json.dumps(self.G, cls=JSONSerializer))
iterencode()
实现。