如何保存对象字典?

时间:2023-01-11 03:46:38

I have a Python 3.5 program that creates an inventory of objects. I created a class of Trampolines (color, size, spring, etc.). I constantly will create new instances of the class and I then save a dictionary of them. The dictionary looks like this:

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

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

My issue is that I want to know how to save this inventory list so that I can start where I left off the last time I closed the program.

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

I don't want to use pickle because I'm trying to learn secure ways to do this for more important versions in the future.

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

I thought about using sqlite3, so any tips on how to do this easily would be appreciated.

我想过使用sqlite3,所以任何有关如何轻松完成此任务的提示都将受到赞赏。

My preferred solution would state how to do it with the json module. I tried it, but the error I got was:

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

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

Edit:

编辑:

Below is the code I used when I got the error:

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

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

End of Edit

编辑结束

I've done a good amount of research, and saw that there's also an issue with many of these save options that you can only do one object per 'save file', but that the work around to this is that you use a dictionary of objects, such as the one I made. Any info clarifying this would be great, too!

我已经做了大量的研究,并发现许多这些保存选项也存在一个问题,你只能为每个'保存文件'做一个对象,但是解决这个问题的方法是使用一个字典对象,例如我制作的对象。澄清这一点的任何信息都会很棒!

3 个解决方案

#1


1  

Here is an example of a class that handles datetime objects.

以下是处理datetime对象的类的示例。

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)

when you encode to json the default function of the cls is called with object you passed. If you want to handle a type that is not part of the standard json.JSONEncoder.default you need to intercept it and return how you want it handled as a valid json type. In this example I turned the datetime into a str and returned that. If its not one of the types I want to special case, I just pass it along to the standard json.JSONEncoder.default handler.

当你编码为json时,使用你传递的对象调用cls的默认函数。如果要处理不属于标准json.JSONEncoder.default的类型,则需要拦截它并返回将其作为有效json类型处理的方式。在这个例子中,我将日期时间转换为str并返回。如果它不是我想要特殊情况的类型之一,我只是将它传递给标准的json.JSONEncoder.default处理程序。

To use this class you need to pass it in the cls param of json.dump or json.dumps:

要使用此类,您需要在json.dump或json.dumps的cls参数中传递它:

json.dumps(obj, cls=CustomEncoder)

Decoding is done the same way but with json.JSONDecoder, json.load, and json.loads. However you can not match on type, so you will need to either add an 'hint' in encoding for decoding or know what type it needs to decode.

使用json.JSONDecoder,json.load和json.loads以相同的方式完成解码。但是,您无法匹配类型,因此您需要在编码中添加“提示”以进行解码,或者知道需要解码的类型。

#2


1  

What you might be able to do is saving the instance's attributes to a CSV-file and then just create it when starting up. This might be a bit too much code and is possible not the best way. One obvious problem is that it doesn't work if you don't have the same amount of attributes as parameters, which should be possible to fix if necessary I believe. I just thought I might try and post and see if it helps :)

您可以做的是将实例的属性保存到CSV文件,然后在启动时创建它。这可能有点太多代码,可能不是最好的方法。一个显而易见的问题是,如果你没有与参数相同数量的属性,它就不起作用,如果有必要我应该可以修复。我只是觉得我可能会尝试发帖,看看是否有帮助:)

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())]))

#3


0  

For a simple class, you can make an easy serializer as below. This will take all of the properties of your Trampoline object and put them into a dictionary and then into JSON.

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

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

If your class is a bit more complicated, then write a more complicated serializer :)

如果你的类有点复杂,那么写一个更复杂的序列化程序:)

#1


1  

Here is an example of a class that handles datetime objects.

以下是处理datetime对象的类的示例。

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)

when you encode to json the default function of the cls is called with object you passed. If you want to handle a type that is not part of the standard json.JSONEncoder.default you need to intercept it and return how you want it handled as a valid json type. In this example I turned the datetime into a str and returned that. If its not one of the types I want to special case, I just pass it along to the standard json.JSONEncoder.default handler.

当你编码为json时,使用你传递的对象调用cls的默认函数。如果要处理不属于标准json.JSONEncoder.default的类型,则需要拦截它并返回将其作为有效json类型处理的方式。在这个例子中,我将日期时间转换为str并返回。如果它不是我想要特殊情况的类型之一,我只是将它传递给标准的json.JSONEncoder.default处理程序。

To use this class you need to pass it in the cls param of json.dump or json.dumps:

要使用此类,您需要在json.dump或json.dumps的cls参数中传递它:

json.dumps(obj, cls=CustomEncoder)

Decoding is done the same way but with json.JSONDecoder, json.load, and json.loads. However you can not match on type, so you will need to either add an 'hint' in encoding for decoding or know what type it needs to decode.

使用json.JSONDecoder,json.load和json.loads以相同的方式完成解码。但是,您无法匹配类型,因此您需要在编码中添加“提示”以进行解码,或者知道需要解码的类型。

#2


1  

What you might be able to do is saving the instance's attributes to a CSV-file and then just create it when starting up. This might be a bit too much code and is possible not the best way. One obvious problem is that it doesn't work if you don't have the same amount of attributes as parameters, which should be possible to fix if necessary I believe. I just thought I might try and post and see if it helps :)

您可以做的是将实例的属性保存到CSV文件,然后在启动时创建它。这可能有点太多代码,可能不是最好的方法。一个显而易见的问题是,如果你没有与参数相同数量的属性,它就不起作用,如果有必要我应该可以修复。我只是觉得我可能会尝试发帖,看看是否有帮助:)

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())]))

#3


0  

For a simple class, you can make an easy serializer as below. This will take all of the properties of your Trampoline object and put them into a dictionary and then into JSON.

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

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

If your class is a bit more complicated, then write a more complicated serializer :)

如果你的类有点复杂,那么写一个更复杂的序列化程序:)