раздел 04
JSON: структура и вложенность
JSON - самый важный формат в вебе. На нём общаются почти все API, в нём хранят настройки, конфиги и данные приложений. Если CSV - это плоская таблица, то JSON - это дерево: внутри значений могут лежать другие значения, списки и объекты. Именно это делает его таким универсальным.
Что это
JSON (JavaScript Object Notation) описывает данные парами «ключ - значение» и списками. Выглядит почти как то, как вы устно описали бы объект.
{
"name": "Анна",
"age": 28,
"city": "Москва",
"phones": ["+7900...", "+7901..."],
"active": true
}
Здесь сразу видно то, чего не умеет CSV: phones - это список из нескольких значений внутри одной записи. И типы честные: age - число, active - логическое значение, name - строка.
Зачем это
JSON берут, когда:
- у данных есть структура и вложенность (объект внутри объекта, списки);
- важны типы: число, строка, true/false, null;
- данные передаются между программами по сети (это язык по умолчанию для API);
- нужно хранить конфиг или настройки в читаемом виде.
Практически весь современный веб держится на JSON: фронтенд просит данные у сервера и получает JSON, отправляет форму - тоже JSON.
Как это работает
Во всех языках есть встроенное превращение JSON в объекты программы и обратно. Это две операции: «разобрать текст в объект» (parse) и «превратить объект в текст» (stringify / dump).
import json
data = {
"name": "Анна",
"tasks": ["купить молоко", "позвонить маме"],
"done": False,
}
# объект -> текст и запись в файл
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# чтение файла -> объект
with open("data.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["tasks"][0]) # купить молоко
Два полезных параметра при записи в Python:
ensure_ascii=False- чтобы русский текст сохранялся как есть, а не какАн...;indent=2- чтобы файл был с отступами и читался глазами.
В JavaScript то же самое ещё короче:
const data = { name: "Анна", tasks: ["купить молоко"], done: false };
const text = JSON.stringify(data, null, 2); // объект -> текст
const obj = JSON.parse(text); // текст -> объект
Пример: JSON как маленькая база данных
Для прототипа JSON-файл часто заменяет базу. Читаем весь файл, меняем в памяти, пишем обратно.
import json
def add_task(text, path="tasks.json"):
try:
with open(path, "r", encoding="utf-8") as f:
tasks = json.load(f)
except FileNotFoundError:
tasks = [] # первый запуск
tasks.append({"text": text, "done": False})
with open(path, "w", encoding="utf-8") as f:
json.dump(tasks, f, ensure_ascii=False, indent=2)
add_task("сдать отчёт")
Для десятков и сотен записей это отлично работает. Тысячи и десятки тысяч - уже тяжело: каждый раз перечитывать и переписывать весь файл становится медленно, и одновременная запись из двух мест всё ломает. Тогда пора в базу данных.
Где у JSON потолок
JSON хранит данные целиком одним куском. Чтобы изменить одну запись, нужно прочитать и переписать весь файл. Нет встроенного поиска - ищете перебором в коде. Нет защиты от одновременной записи. Всё это решает база данных - раздел 05.
Антипаттерны
- Хранить в одном JSON-файле гигантские объёмы. Перезапись всего файла ради одной правки на больших данных - это медленно. Сигнал к базе.
- Забыть
ensure_ascii=Falseв Python - и получить нечитаемыеАвместо русских букв (работать будет, но глазами не прочитать). - Лишняя запятая в конце. В JSON нельзя ставить запятую после последнего элемента - это самая частая синтаксическая ошибка. Подробнее на странице про вложенность.