JSON в Python: модуль json
Как работать с JSON в Python: json.dumps и json.loads, запись и чтение файла через dump и load, кириллица и ensure_ascii, indent, сериализация datetime.
Содержание · 10 разделов
- Четыре функции модуля json
- json.dumps: объект Python в строку JSON
- ensure_ascii=False: кириллица без экранирования
- indent, sort_keys и separators: форматирование
- json.loads: строка JSON в объект Python
- Соответствие типов Python и JSON
- Запись и чтение JSON-файла: dump и load
- Сериализация datetime и других типов
- Свой JSONEncoder и dataclass
- Проверка и форматирование JSON из командной строки
- Частые ошибки
- JSONDecodeError: Expecting property name enclosed in double quotes
- JSONDecodeError: Expecting value: line 1 column 1 (char 0)
- Перепутали load и loads
- Кракозябры или UnicodeDecodeError при чтении файла
- NaN в результате
- Частые вопросы
- Что значит ошибка Unexpected UTF-8 BOM?
- Как прочитать файл, где на каждой строке свой JSON?
- Как обращаться к полям JSON через точку, а не по ключу?
- Как разобрать строку в одинарных кавычках, если исправить источник нельзя?
- Чем json отличается от pickle?
- Итог
Для работы с JSON в Python есть встроенный модуль json — ничего устанавливать не нужно. Короткий ответ: json.dumps(obj) превращает словарь или список в строку JSON, json.loads(text) — строку обратно в объекты Python, а json.dump() и json.load() делают то же самое с файлами. Для читаемой кириллицы передавайте ensure_ascii=False.
В статье — четыре основные функции модуля, соответствие типов Python и JSON, форматирование, запись и чтение файлов, сериализация datetime и разбор типичных ошибок. Примеры проверены на Python 3.12, вывод показан комментарием # →.
Четыре функции модуля json
| Функция | Что делает | Работает с |
|---|---|---|
json.dumps(obj) | объект Python → строка JSON | строкой |
json.loads(text) | строка JSON → объект Python | строкой |
json.dump(obj, file) | объект Python → запись JSON в файл | файлом |
json.load(file) | чтение JSON из файла → объект Python | файлом |
Запомнить просто: буква s на конце означает string — функция работает со строкой.
json.dumps: объект Python в строку JSON
import json
user = {"name": "Анна", "age": 30, "admin": True, "tags": ["dev", "ops"], "phone": None}
text = json.dumps(user)
print(text)
# → {"name": "\u0410\u043d\u043d\u0430", "age": 30, "admin": true, "tags": ["dev", "ops"], "phone": null}
print(type(text)) # → <class 'str'>
True стал true, None — null, а кириллица превратилась в последовательности вида \u0410. Это корректный JSON, и любой парсер прочитает его правильно, но человеку такой текст неудобен.
ensure_ascii=False: кириллица без экранирования
По умолчанию ensure_ascii=True, и все не-ASCII символы экранируются. Отключите это, чтобы кириллица осталась читаемой:
print(json.dumps(user, ensure_ascii=False))
# → {"name": "Анна", "age": 30, "admin": true, "tags": ["dev", "ops"], "phone": null}
indent, sort_keys и separators: форматирование
print(json.dumps(user, ensure_ascii=False, indent=2))
{
"name": "Анна",
"age": 30,
"admin": true,
"tags": [
"dev",
"ops"
],
"phone": null
}
print(json.dumps({"b": 1, "a": 2}, sort_keys=True)) # → {"a": 2, "b": 1}
print(json.dumps({"a": 1, "b": [1, 2]}, separators=(",", ":"))) # → {"a":1,"b":[1,2]}
indent задаёт отступ для «красивого» вывода, sort_keys=True сортирует ключи (удобно для сравнения файлов в git), а separators=(",", ":") убирает пробелы и делает JSON максимально компактным для передачи по сети.
json.loads: строка JSON в объект Python
data = json.loads('{"name": "Анна", "age": 30, "admin": true, "phone": null}')
print(data) # → {'name': 'Анна', 'age': 30, 'admin': True, 'phone': None}
print(type(data)) # → <class 'dict'>
print(data["age"] + 1) # → 31
Верхним уровнем JSON может быть не только объект: json.loads("[1, 2.5, \"x\", false]") вернёт список [1, 2.5, 'x', False], а json.loads("42") — число 42.
Соответствие типов Python и JSON
| Python | JSON | Обратно в Python |
|---|---|---|
dict | object | dict |
list, tuple | array | list |
str | string | str |
int, float | number | int / float |
True / False | true/false | True / False |
None | null | None |
Из таблицы следуют две неочевидные вещи: кортеж после «круга» через JSON возвращается списком, а ключи словаря в JSON всегда строки — числовой ключ станет строковым:
print(json.loads(json.dumps({1: "a", "t": (1, 2)}))) # → {'1': 'a', 't': [1, 2]}
Подробнее о словарях и их ключах — в статье о словарях в Python.
Запись и чтение JSON-файла: dump и load
json.dump() пишет JSON прямо в открытый файл, json.load() читает из него. Всегда указывайте encoding="utf-8". Без него Python до версии 3.14 включительно берёт кодировку системы: на Windows с русской локалью это cp1251, и файл в UTF-8 читается с ошибками. С Python 3.15 по умолчанию включён режим UTF-8 (PEP 686), но явная кодировка делает код независимым от версии и настроек.
import json
config = {"debug": True, "db": {"host": "localhost", "port": 5432}, "title": "Мой сайт"}
with open("config.json", "w", encoding="utf-8") as f:
json.dump(config, f, ensure_ascii=False, indent=2)
with open("config.json", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["db"]["port"], loaded["title"]) # → 5432 Мой сайт
Содержимое config.json:
{
"debug": true,
"db": {
"host": "localhost",
"port": 5432
},
"title": "Мой сайт"
}
Конструкция with сама закроет файл даже при ошибке. Ответы веб-API обычно тоже приходят в JSON: в библиотеке requests для их разбора есть готовый метод response.json() — подробнее в статье о библиотеке requests.
Сериализация datetime и других типов
Модуль json умеет сериализовать только типы из таблицы выше. Дата, Decimal, множество или объект класса вызовут ошибку:
from datetime import datetime, timezone
order = {"id": 7, "created": datetime(2026, 10, 9, 14, 30, tzinfo=timezone.utc)}
json.dumps(order)
# → TypeError: Object of type datetime is not JSON serializable
Быстрое решение — default=str: функция вызывается для каждого неподдерживаемого объекта.
print(json.dumps(order, default=str))
# → {"id": 7, "created": "2026-10-09 14:30:00+00:00"}
Надёжнее написать свою функцию и выводить даты в формате ISO 8601 через isoformat() — его понимают JavaScript, базы данных и большинство API:
from datetime import date, datetime, timezone
from decimal import Decimal
def to_json(obj):
if isinstance(obj, (datetime, date)):
return obj.isoformat()
if isinstance(obj, Decimal):
return str(obj)
if isinstance(obj, set):
return sorted(obj)
raise TypeError(f"Тип {type(obj).__name__} не сериализуется в JSON")
order = {
"id": 7,
"created": datetime(2026, 10, 9, 14, 30, tzinfo=timezone.utc),
"total": Decimal("1999.90"),
"tags": {"new", "paid"},
}
text = json.dumps(order, default=to_json)
print(text)
# → {"id": 7, "created": "2026-10-09T14:30:00+00:00", "total": "1999.90", "tags": ["new", "paid"]}
Обратно JSON возвращает строку, а не дату. Преобразуйте её явно через datetime.fromisoformat():
data = json.loads(text)
created = datetime.fromisoformat(data["created"])
print(repr(created))
# → datetime.datetime(2026, 10, 9, 14, 30, tzinfo=datetime.timezone.utc)
Если даты в JSON узнаются по имени ключа, преобразование можно автоматизировать параметром object_hook — функция получает каждый разобранный словарь:
def parse_dates(d):
for key, value in d.items():
if key.endswith("_at"):
d[key] = datetime.fromisoformat(value)
return d
print(json.loads('{"id": 1, "created_at": "2026-10-09T14:30:00+00:00"}', object_hook=parse_dates))
# → {'id': 1, 'created_at': datetime.datetime(2026, 10, 9, 14, 30, tzinfo=datetime.timezone.utc)}
О форматах дат, часовых поясах и isoformat() подробно рассказано в статье о datetime в Python.
Свой JSONEncoder и dataclass
Ту же логику можно оформить классом-наследником json.JSONEncoder и передавать через cls=. Для неизвестных типов вызывайте super().default(obj) — он выбросит стандартный TypeError:
class AppEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, (datetime, date)):
return obj.isoformat()
return super().default(obj)
print(json.dumps({"day": date(2026, 10, 9)}, cls=AppEncoder)) # → {"day": "2026-10-09"}
Объекты dataclass сначала превратите в словарь функцией dataclasses.asdict(). Если нужна полноценная валидация входящего JSON по схеме, посмотрите на Pydantic: его модели умеют и разбирать JSON, и сериализовать даты.
Проверка и форматирование JSON из командной строки
Модуль json можно запустить как утилиту: она проверит синтаксис файла и выведет его с отступами.
python -m json.tool config.json
python -m json.tool --no-ensure-ascii --sort-keys config.json
На Windows вместо python может понадобиться py. Если JSON некорректен, утилита покажет ошибку с номером строки и столбца.
Частые ошибки
JSONDecodeError: Expecting property name enclosed in double quotes
В JSON строки и ключи пишутся только в двойных кавычках, а запятая после последнего элемента запрещена:
json.loads("{'name': 'Анна'}")
# → json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
json.loads('{"a": 1,}')
# → json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 9 (char 8)
В Python 3.13 и новее для лишней запятой сообщение точнее: Illegal trailing comma before end of object: line 1 column 8 (char 7).
Частая причина — попытка разобрать результат str(dict) или print(dict): такой текст записан в синтаксисе Python, и парсер JSON его не примет. Для сериализации всегда используйте json.dumps().
JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Парсер получил пустую строку или текст, который вообще не начинается как JSON: пустой файл, HTML-страницу с ошибкой вместо ответа API, слово None. Выведите исходный текст и проверьте, что там действительно JSON. JSONDecodeError — подкласс ValueError, его удобно ловить через try/except.
Перепутали load и loads
json.load() ждёт открытый файл, а не имя файла: json.load("config.json") выбросит AttributeError: 'str' object has no attribute 'read'. Откройте файл через open() или прочитайте строку и вызовите json.loads().
Кракозябры или UnicodeDecodeError при чтении файла
Файл открыт без encoding="utf-8", и Python прочитал его в кодировке системы — на Windows до Python 3.15 это обычно cp1251 или cp1252. Указывайте кодировку явно и при записи, и при чтении.
NaN в результате
json.dumps(float("nan")) вернёт NaN — Python это допускает, но по стандарту JSON такого значения нет, и строгие парсеры (например, в браузере) его не примут. Передайте allow_nan=False, чтобы получить ValueError заранее.
Частые вопросы
Что значит ошибка Unexpected UTF-8 BOM?
Файл сохранён в кодировке «UTF-8 с BOM» — так сохраняют файлы Блокнот в старых версиях Windows и Windows PowerShell 5.1. В начале файла стоит служебный символ, который json не принимает: JSONDecodeError: Unexpected UTF-8 BOM (decode using utf-8-sig). Откройте файл с кодировкой utf-8-sig, она пропускает BOM:
with open("data.json", encoding="utf-8-sig") as f:
data = json.load(f)
Как прочитать файл, где на каждой строке свой JSON?
Это формат JSON Lines (.jsonl), в нём хранят логи и выгрузки. json.load() на таком файле упадёт с Extra data, поэтому разбирайте строки по одной:
with open("events.jsonl", encoding="utf-8") as f:
events = [json.loads(line) for line in f if line.strip()]
print(events) # → [{'id': 1, 'type': 'login'}, {'id': 2, 'type': 'logout'}]
Как обращаться к полям JSON через точку, а не по ключу?
Передайте в object_hook класс SimpleNamespace — каждый словарь станет объектом с атрибутами:
from types import SimpleNamespace
cfg = json.loads('{"db": {"host": "localhost", "port": 5432}}',
object_hook=lambda d: SimpleNamespace(**d))
print(cfg.db.port) # → 5432
Для данных с проверкой типов лучше подходят модели Pydantic.
Как разобрать строку в одинарных кавычках, если исправить источник нельзя?
Если строка — это напечатанный словарь Python, используйте ast.literal_eval(): он безопасно разбирает литералы Python (True, None, одинарные кавычки) и не выполняет код. ast.literal_eval("{'name': 'Анна', 'active': True}") вернёт словарь. Функцию eval() для этого не применяйте.
Чем json отличается от pickle?
json пишет текст, который читают любые языки и сервисы, но поддерживает только базовые типы. pickle сохраняет почти любой объект Python в двоичном виде, но формат понятен только Python, а загрузка pickle из недоверенного источника позволяет выполнить произвольный код. Для обмена данными и конфигов выбирайте JSON.
Итог
Для JSON в Python достаточно четырёх функций: dumps и loads для строк, dump и load для файлов. Для кириллицы добавляйте ensure_ascii=False, для читаемости — indent=2, при работе с файлами — encoding="utf-8", а даты сериализуйте через default и isoformat(). Другие модули стандартной библиотеки и конструкции языка собраны в шпаргалке по синтаксису Python.
- #Python
- #JSON
- #json
- #Сериализация
- #Стандартная библиотека