Глава 15 · Python и файлы

JSON: сохраняем структуры данных

Словари и списки из главы 11 наконец получают надёжный способ пережить перезапуск программы.

Модуль json

json_dump.py
import json

data = {"name": "Anna", "score": 1200}

with open("igrok.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)
$ cat igrok.json
{
  "name": "Anna",
  "score": 1200
}
Реально сохранённый файл — самый обычный текст, его можно открыть в любом редакторе.
json_load.py
import json

with open("igrok.json", "r", encoding="utf-8") as f:
    data = json.load(f)

print(type(data))   # <class 'dict'>
print(data["name"])   # Anna

dump/load vs dumps/loads

ФункцияЧто делает
json.dump(data, file)пишет JSON прямо в открытый файловый объект
json.dumps(data)возвращает JSON как обычную строку str
json.load(file)читает JSON из открытого файлового объекта
json.loads(text)разбирает JSON из готовой строки str

Соответствие типов JSON ↔ Python

JSONPython
objectdict
arraylist
stringstr
numberint / float
true / falseTrue / False
nullNone

Что JSON не умеет напрямую

JSON не сохраняет произвольный объект Python сам
set, экземпляр собственного класса, bytes, complex — все они не имеют прямого представления в JSON. json.dump() не умеет «магически» сохранить произвольный объект Python — сначала нужно самостоятельно привести данные к словарям/спискам/строкам/числам.
Кортеж при чтении вернётся списком
Если сохранить tuple как JSON-массив, при загрузке обратно вы получите обычный list, а не tuple — JSON не различает эти два типа Python, у него есть только один вид «массив».
Debug Lab 12: Некорректный JSON в файле
slomanny_json.py
with open("nastroyki.json", "w", encoding="utf-8") as f:
    f.write('{"theme": "dark",}')   # лишняя запятая перед }

import json
with open("nastroyki.json", "r", encoding="utf-8") as f:
    data = json.load(f)
Traceback (most recent call last):
json.decoder.JSONDecodeError: Illegal trailing comma before end of object: line 1 column 17 (char 16)
Что видно на экране

Наличие файла не означает, что его содержимое — корректный JSON: файл мог быть повреждён, отредактирован вручную или записан с ошибкой в другом месте программы. json.JSONDecodeError — сигнал именно об этом, а не о проблеме с путём или правами доступа.

Исправленный код
json_bez_zapyatoj.py
with open("nastroyki.json", "w", encoding="utf-8") as f:
    f.write('{"theme": "dark"}')

Мини-проект: менеджер настроек

Настройки приложения, которые нужно будет использовать в графическом приложении главы 16 — с понятными значениями по умолчанию, если файла ещё нет:

nastroyki_menedzher.py
import json
from pathlib import Path

DEFAULT_SETTINGS = {"theme": "light", "language": "ru", "window_width": 900}

def load_settings(path: Path) -> dict:
    if not path.exists():
        return dict(DEFAULT_SETTINGS)
    with path.open("r", encoding="utf-8") as f:
        return json.load(f)

def save_settings(path: Path, settings: dict) -> None:
    with path.open("w", encoding="utf-8") as f:
        json.dump(settings, f, ensure_ascii=False, indent=2)

settings_path = Path("nastroyki.json")
settings = load_settings(settings_path)
settings["theme"] = "dark"
save_settings(settings_path, settings)
Готовим почву для главы 16
Именно так графическое приложение на Tkinter (глава 16) сможет запоминать настройки пользователя между запусками — загружать их при старте и сохранять при изменении, без единой строчки кода интерфейса в этой функции.
Практика: JSON и менеджер настроек
Интерактивный ноутбук прямо в браузере — Python 3.14 через Pyodide, без установки
Открыть практику →