Формат JSON
Представьте переезд. Шкаф целиком в почтовую посылку не влезет. Его разбирают на плоские доски, кладут в коробку инструкцию по сборке, а на новом месте собирают заново. Получается такой же шкаф, хотя это уже другая сборка.
С данными программы происходит то же самое. Метод write записывает в файл только строки, а данные программы — это словари, списки, числа. Их нужно превратить в строку, а потом собрать обратно. Такое превращение называют сериализацией.
Самый распространённый текстовый формат для неё — JSON. Это как стандартная коробка, которую принимает любая служба доставки: JSON читают программы на любом языке. В Python с ним работает модуль json:
import json
data = {"name": "Ann", "langs": ["python", "go"], "admin": False}
text = json.dumps(data)
print(text) # {"name": "Ann", "langs": ["python", "go"], "admin": false}
back = json.loads(text)
print(back["langs"][0], back == data) # python TrueДавайте разберём пример по строкам:
data— обычный словарь со строкой, списком иFalse.json.dumps(data)упаковывает словарь в строкуtext.print(text)показывает, как выглядит JSON: почти как словарь Python, ноFalseпревратился вfalse.json.loads(text)разбирает строку и строит из неё новые объекты Python.- Последняя строка печатает
python True: собранный словарь равен исходному.
Как пишется JSON
У JSON свои правила записи, и они чуть строже, чем у Python:
- строки стоят только в двойных кавычках;
TrueиFalseпишутся какtrueиfalse, аNone— какnull;- словарь в JSON называется объектом, а список — массивом.
Аргумент indent=2 в json.dumps разбивает текст на строки с отступом в два пробела. Такой файл удобно читать и править вручную.
Что меняется по дороге
Здесь аналогия с переездом заканчивается: шкаф собирают ровно таким, каким он был, а данные иногда приезжают другими. JSON знает только объекты, массивы, строки, числа, true, false и null. Поэтому кортеж записывается массивом и возвращается списком, а ключи объекта всегда строки — число 1 в ключе станет строкой "1":
import json
data = {1: "one", "pair": (1, 2)}
back = json.loads(json.dumps(data))
print(back) # {'1': 'one', 'pair': [1, 2]}
print([1, 2] == (1, 2), back == data) # False FalseСтроки, числа, списки и словари со строковыми ключами возвращаются такими же, какими ушли. Список никогда не равен кортежу, даже с теми же элементами, поэтому back и data уже не равны.
Множество JSON не принимает вовсе: json.dumps({1, 2}) вызывает TypeError: Object of type set is not JSON serializable. Перед упаковкой его превращают в список, например через sorted.
JSON и файлы
Для файлов есть пара функций без буквы s на конце:
json.dump(data, f)пишет данные в открытый файл;json.load(f)читает их из файла.
Так программа сохраняет настройки между запусками. В браузере, где выполняются задачи курса, файлов вашего компьютера нет, поэтому в задачах работают со строками и json.loads.
Частая ошибка
Строку JSON написали с одинарными кавычками, как в Python:
import json
settings = json.loads("{'theme': 'dark'}") # ✗json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)Конец сообщения указывает место ошибки: символ с индексом 1, где JSON ждал двойную кавычку. JSON принимает строки только в двойных кавычках: '{"theme": "dark"}'. Класс json.JSONDecodeError наследует от ValueError, поэтому неверный JSON ловит и except ValueError.
Главное
json.dumpsпревращает данные в строку JSON, аjson.loadsсобирает из строки новые объекты.- В JSON строки только в двойных кавычках, а
True,FalseиNoneпишутся какtrue,falseиnull. - Кортеж возвращается списком, ключ-число — строкой, а множество в JSON не записать.
- Неверный JSON вызывает
json.JSONDecodeError, потомкаValueError.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.