Как сохранить словарь объектов?
У меня есть программа Python 3.5, которая создает инвентаризацию объектов. Я создал класс Trampoline
s (цвет, размер, весна и т. д.). Я постоянно создаю новые экземпляры класса, а затем сохраняю их словарь. Словарь выглядит так:
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))
Если ваш класс немного сложнее, напишите более сложный сериализатор:)