如何保存对象字典?

How to save a dictionary of objects?

我有一个 Python 3.5 程序可以创建对象清单。我创建了 class 个 Trampoline(颜色、大小、spring 等)。我会不断创建 class 的新实例,然后保存它们的字典。字典看起来像这样:

my_dict = {name: instance} and the types are like so {"string": "object"}

我的问题是我想知道如何保存这个库存清单,以便我可以从上次关闭程序时离开的地方开始。

我不想使用 pickle,因为我正在尝试学习安全的方法来为将来更重要的版本执行此操作。

我考虑过使用 sqlite3,所以任何关于如何轻松做到这一点的提示都将不胜感激。

我的首选解决方案是说明如何使用 json 模块。我试过了,但我得到的错误是:

__main__.Trampoline object at 0x00032432... is not JSON serializable

编辑:

下面是我遇到错误时使用的代码:

out_file = open(input("What do you want to save it as?  "), "w")
json.dump(my_dict, out_file, indent=4)
out_file.close()

编辑结束

我做了很多研究,发现其中许多 保存 选项也存在问题,您只能执行 一个 object per 'save file',但是解决这个问题的方法是使用对象字典,比如我制作的字典。任何澄清这一点的信息也很棒!

对于简单的class,您可以制作一个简单的序列化器,如下所示。这将获取 Trampoline 对象的所有属性并将它们放入字典,然后放入 JSON。

class Trampoline(object):
    ...
    def serialize(self):
        return json.dumps(vars(self))

如果你的class有点复杂,那就写一个更复杂的序列化器:)

您可以将实例的属性保存到 CSV 文件中,然后在启动时创建它。这可能是代码太多,可能不是最好的方法。一个明显的问题是,如果您没有与参数相同数量的属性,它就不起作用,我相信如果有必要,应该可以解决这个问题。我只是想我可以尝试 post 看看是否有帮助:)

import json


class Trampoline:
    def __init__(self, color, size, height, spring):
        self.color = color
        self.size = size
        self.height = height
        self.spring = spring

    def __repr__(self):
        return "Attributes: {}, {}, {}, {}".format(self.color, self.size, self.height, self.spring)


my_dict = {
    "name1": Trampoline('red', 100, 2.3, True),
    "name2": Trampoline('blue', 50, 2.1, False),
    "name3": Trampoline('green', 25, 1.8, True),
    "name5": Trampoline('white', 10, 2.6, False),
    "name6": Trampoline('black', 0, 1.4, True),
    "name7": Trampoline('purple', -33, 3.0, True),
    "name8": Trampoline('orange', -999, 2.5, False),
}


def save(my_dict):
    with open('save_file.txt', 'w') as file:
        temp = {}
        for name, instance in my_dict.items():
            attributes = {}
            for attribute_name, attribute_value in instance.__dict__.items():
                attributes[attribute_name] = attribute_value
            temp[name] = attributes
        json.dump(temp, file)


def load():
    with open('save_file.txt', 'r') as file:
        my_dict = {}
        x = json.load(file)
        for name, attributes in x.items():
            my_dict[name] = Trampoline(**attributes)
    return my_dict


# CHECK IF IT WORKS!
save(my_dict)
my_dict = load()
print("\n".join(["{}  |  {}".format(name, instance) for name, instance in sorted(my_dict.items())]))

这是一个处理日期时间对象的 class 示例。

class CustomEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            if obj.tzinfo:
                obj = obj.astimezone(isodate.tzinfo.UTC).replace(tzinfo=None)
            return obj.isoformat()[:23] + 'Z'
        return json.JSONEncoder.default(self, obj)

当您编码为 json 时,将使用您传递的对象调用 clsdefault 函数。如果你想处理一个不属于标准 json.JSONEncoder.default 的类型,你需要拦截它并且 return 你希望它如何作为有效的 json 类型处理。在这个例子中,我把 datetime 变成了 str 并且 return 编辑了它。如果它不是我想要特殊情况的类型之一,我只是将它传递给标准 json.JSONEncoder.default 处理程序。

要使用此 class,您需要将其传递到 json.dumpjson.dumpscls 参数中:

json.dumps(obj, cls=CustomEncoder)

解码以相同的方式完成,但使用 json.JSONDecoderjson.loadjson.loads。但是你不能匹配类型,所以你需要在解码编码中添加一个 'hint' 或者知道它需要解码什么类型。