Глава 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
| JSON | Python |
|---|---|
| object | dict |
| array | list |
| string | str |
| number | int / float |
| true / false | True / False |
| null | None |
Что 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, без установки