SmartQuery /ВОПРОС → ПРИМЕР → ПОНЯТНЫЙ ОТВЕТ
Языки и платформы

Изменить 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 не сохраняет комментарии и исходное форматирование как редактор текста. Для недоверенного ввода ограничьте размер. При замене меняется сам файл: при необходимости отдельно сохраните требуемые права доступа и метаданные. При замене меняется сам файл: при необходимости отдельно сохраните требуемые права доступа и метаданные. При одновременной записи несколькими процессами нужны отдельные блокировки/хранилище; временный файл сам по себе этого не решает.

Документация