Изменить JSON-файл в Python и не затереть его при ошибке
json.load читает JSON в объекты Python: объект становится dict, массив — list. Операции data["key"] и data[0] относятся к разным типам корня и не должны безусловно выполняться подряд над одним документом.
Пример для объекта
import json
import tempfile
from pathlib import Path
path = Path("file.json")
data = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(data, dict):
raise ValueError("Ожидался JSON-объект")
data["key"] = "новое значение"
text = json.dumps(data, ensure_ascii=False, indent=2) + "\n"
temporary = None
try:
with tempfile.NamedTemporaryFile(
mode="w", encoding="utf-8", dir=path.parent,
prefix=path.name + ".", suffix=".tmp", delete=False
) as stream:
temporary = Path(stream.name)
stream.write(text)
temporary.replace(path)
finally:
if temporary is not None:
temporary.unlink(missing_ok=True)Сначала сохраните независимую резервную копию важного файла. Пример пишет временный файл в том же каталоге и не открывает исходник на запись до успешного разбора и сериализации. Он предназначен для одиночного локального процесса, а не для конкурентной базы данных.
Если корень — массив
Проверьте isinstance(data, list) и наличие нужного индекса перед изменением. Не преобразуйте структуру наугад только ради отсутствия исключения.
Ограничения
Обработайте JSONDecodeError, отказ доступа и ошибки диска. json не сохраняет комментарии и исходное форматирование как редактор текста. Для недоверенного ввода ограничьте размер. При замене меняется сам файл: при необходимости отдельно сохраните требуемые права доступа и метаданные. При замене меняется сам файл: при необходимости отдельно сохраните требуемые права доступа и метаданные. При одновременной записи несколькими процессами нужны отдельные блокировки/хранилище; временный файл сам по себе этого не решает.