Как сохранить словарь объектов?

У меня есть программа Python 3.5, которая создает инвентаризацию объектов. Я создал класс Trampolines (цвет, размер, весна и т. д.). Я постоянно создаю новые экземпляры класса, а затем сохраняю их словарь. Словарь выглядит так:

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

Конец редактирования

Я провел большое количество исследований и обнаружил, что во многих из этих опций сохранения есть проблема, заключающаяся в том, что вы можете сделать только один объект на "файл сохранения", но что обойти это можно, используя словарь объекты, такие как тот, который я сделал. Любая информация, разъясняющая это, тоже была бы отличной!

3 ответа

Решение

Вот пример класса, который обрабатывает объекты даты и времени.

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 default функция cls вызывается с объектом, который вы передали. Если вы хотите обрабатывать тип, который не является частью стандарта json.JSONEncoder.default вам нужно перехватить его и вернуть, как вы хотите, чтобы он обрабатывался как допустимый тип json. В этом примере я перевернул datetime в str и вернул это. Если это не один из типов, которые я хочу, чтобы особый случай, я просто передаю его в стандарт json.JSONEncoder.default обработчик.

Чтобы использовать этот класс, вам нужно передать его в cls параметр json.dump или же json.dumps:

json.dumps(obj, cls=CustomEncoder)

Декодирование выполняется так же, но с json.JSONDecoder, json.load, а также json.loads, Однако вы не можете сопоставить тип, поэтому вам нужно либо добавить "подсказку" в кодировку для декодирования, либо знать, какой тип нужно декодировать.

То, что вы могли бы сделать, это сохранить атрибуты экземпляра в 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())]))

Для простого класса вы можете создать простой сериализатор, как показано ниже. Это займет все свойства вашего Trampoline объект и положить их в словарь, а затем в JSON.

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

Если ваш класс немного сложнее, напишите более сложный сериализатор:)

Другие вопросы по тегам