Модуль json — работа с JSON в Python
JSON (JavaScript Object Notation) — самый популярный текстовый формат обмена данными в современном вебе. На нём отвечают REST API, в нём хранятся конфиги, и именно в JSON ваш скрипт чаще всего получит данные от внешнего сервиса.
Стандартный модуль Python json умеет превращать Python-объекты в JSON-строку
и обратно. Модуль входит в стандартную библиотеку — никаких установок не нужно:
import json
Зачем нужен JSON
JSON — это компромисс между читаемостью человеком и компактностью для машины. Пример JSON-документа:
{
"id": 42,
"name": "Айдос",
"skills": ["Python", "Arduino"],
"active": true,
"city": null
}
Применения:
REST API. Запросы и ответы почти всегда в JSON.
Конфигурационные файлы.
settings.json,package.jsonи сотни других.Логи событий в современных системах мониторинга.
Сериализация состояния между запусками программы.
Соответствие типов Python ↔ JSON
Python -> JSON
----------------------------
dict -> object
list, tuple -> array
str -> string
int, float -> number
True -> true
False -> false
None -> null
И обратно при чтении. Обратите внимание: JSON не различает list и tuple
— оба превратятся в JSON-array, а назад придут как list.
Сериализация: Python в JSON
Две функции: json.dumps (вернуть строку) и json.dump (записать в файл).
import json
data = {
"name": "Айдос",
"age": 21,
"skills": ["Python", "Arduino"],
}
text = json.dumps(data)
print(text)
# {"name": "Айдос", "age": 21, ...}
Кириллица превратилась в Unicode-escape — это безопасно, но нечитаемо. Лечится
параметром ensure_ascii=False:
text = json.dumps(data, ensure_ascii=False, indent=2)
print(text)
Вывод:
{
"name": "Айдос",
"age": 21,
"skills": [
"Python",
"Arduino"
]
}
Полезные параметры:
indent— отступ для красивого вывода (обычно2или4);ensure_ascii=False— оставить кириллицу как есть;sort_keys=True— отсортировать ключи (удобно для diff и тестов);separators=(',', ':')— компактный формат без пробелов (минимальный размер).
Запись в файл:
with open('user.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
Десериализация: JSON в Python
Симметрично: json.loads (из строки) и json.load (из файла).
import json
text = '{"name": "Айдос", "age": 21}'
data = json.loads(text)
print(data['name']) # Айдос
print(type(data)) # <class 'dict'>
Из файла:
with open('user.json', encoding='utf-8') as f:
data = json.load(f)
Практический пример: ответ от API
Типичная задача — обратиться к веб-API и распарсить ответ:
import json
import urllib.request
url = 'https://api.github.com/repos/python/cpython'
with urllib.request.urlopen(url) as r:
payload = json.load(r)
print('Звёзд:', payload['stargazers_count'])
print('Описание:', payload['description'])
Практический пример: конфиг приложения
Сохраняем настройки между запусками:
import json
from pathlib import Path
CONFIG = Path('config.json')
def load_config():
if CONFIG.exists():
with CONFIG.open(encoding='utf-8') as f:
return json.load(f)
return {'theme': 'light', 'lang': 'ru'}
def save_config(cfg):
with CONFIG.open('w', encoding='utf-8') as f:
json.dump(cfg, f, ensure_ascii=False, indent=2)
cfg = load_config()
cfg['theme'] = 'dark'
save_config(cfg)
Кастомные типы: default и object_hook
json не умеет сериализовать datetime, set, классы и другие
нестандартные объекты. При попытке получите TypeError. Решение — параметр
default:
import json
from datetime import datetime
def encode(obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, set):
return list(obj)
raise TypeError(f'Не знаю, как сериализовать {type(obj)}')
data = {'created': datetime.now(), 'tags': {'python', 'json'}}
print(json.dumps(data, default=encode, ensure_ascii=False))
При обратном чтении используют object_hook — функцию, которая получает
каждый словарь после разбора и может его преобразовать.
Подводные камни
Предупреждение
``ensure_ascii=True`` по умолчанию. Кириллица будет escape’нута. Для человекочитаемых файлов всегда ставьте
False.Ключи словаря в JSON только строки.
json.dumps({1: 'a'})молча превратит ключ в"1".``True`` и ``False`` в JSON — без кавычек и с маленькой буквы. Ручная сборка JSON через
str.formatпочти всегда заканчивается багом — используйтеjson.dumps.NaN и Infinity — не валидный JSON, хотя Python их пишет. Парсер на другой стороне может упасть. Установите
allow_nan=False, чтобы получить ошибку на своей стороне.Безопасность.
json.loadбезопасен сам по себе, но не доверяйте неизвестным размерам — большой JSON может съесть всю память.
JSON Lines (JSONL)
Часто данные хранят в формате JSON Lines — по одному JSON-объекту на строку:
{"id": 1, "name": "Айдос"}
{"id": 2, "name": "Гульнара"}
Это удобно для логов и потоковой обработки больших файлов:
import json
with open('events.jsonl', encoding='utf-8') as f:
for line in f:
event = json.loads(line)
print(event['id'])
Смотрите также
Модуль csv — работа с CSV-файлами в Python — табличный формат-альтернатива
Словари (Dictionary) в Python — словари (главная Python-структура для JSON)
Работа с файлами Python — работа с файлами
Примечание
Лицензия и источники
Часть материала адаптирована из официальной документации Python (https://docs.python.org/3/library/json.html), доступной под Python Software Foundation License Version 2 (PSF License). Адаптация, переработка, оригинальные примеры и пояснения — © AlashEd Wiki.