Как записать данные в JSON-файл в Python через json.dump

Чтобы записать данные в JSON-файл на Python, хватит open() в режиме «w» и json.dump().

Разбираем, чем dump отличается от dumps, как сохранить кириллицу без кодов \u, записать даты и свои классы и дописать запись в готовый файл, не сломав его. У каждого примера кода показан вывод.

Статью написал:
Ваня Буявец, продюсер, основатель Checkroi
Ваня Буявец
Основатель Checkroi, продюсер, эксперт в выборе онлайн-курсов
Все 3139 статей автора Подписаться на Телеграм-канал
Одобрено экспертом:
Наташа Буявец, основатель Checkroi, эксперт по онлайн-курсам
Наташа Буявец
Основательница Checkroi, продюсер Youtube-каналов, эксперт по онлайн-курсам
Все 3793 экспертных мнения Подписаться на Телеграм-канал
Обложка: Как записать данные в JSON-файл в Python через json.dump

Чтобы записать данные в JSON-файл в Python, откройте файл на запись и передайте словарь в json.dump(): with open("user.json", "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=4). Модуль json встроен в Python, ставить ничего не нужно. Параметр ensure_ascii=False сохраняет кириллицу буквами, а не кодами вида \u0410, а indent=4 раскладывает файл по строкам с отступами.

Ниже разберём пошаговую запись, разницу между dump() и dumps(), настройки форматирования, запись дат и своих классов, дописывание в готовый файл и ошибки, на которых чаще всего ломается код. Как устроен сам формат, мы подробно рассказали в статье что такое JSON простыми словами.

CheckroiCheckroiПодборка курсов по Python569 курсов • 52 школыСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Как записать словарь в JSON-файл за четыре шага

Рой сохраняет данные из Python в JSON-файл на ноутбуке

Возьмём типичную задачу: сохранить профиль пользователя, чтобы программа прочитала его при следующем запуске.

  1. Подключите модуль строкой import json. Он входит в стандартную библиотеку.
  2. Соберите данные в словарь или список. JSON-объект в Python читается как dict, массив как list.
  3. Откройте файл в режиме "w" через with open(...) и сразу укажите encoding="utf-8". Если файла нет, Python его создаст, если есть, перезапишет целиком.
  4. Вызовите json.dump(данные, файл) внутри блока with. После выхода из блока файл закроется сам.
import json

user = {
    "name": "Анна",
    "age": 29,
    "skills": ["Python", "SQL"],
    "remote": True,
    "manager": None,
}

with open("user.json", "w", encoding="utf-8") as f:
    json.dump(user, f, ensure_ascii=False, indent=4)

В папке со скриптом появится файл user.json:

{
    "name": "Анна",
    "age": 29,
    "skills": [
        "Python",
        "SQL"
    ],
    "remote": true,
    "manager": null
}

Обратите внимание на замены: True стало true, а None превратилось в null. Так выглядит запись по стандарту JSON, и программа на любом другом языке прочитает этот файл без доработок.

Режимы открытия и пути к файлам мы разобрали отдельно в инструкции как открыть файл в Python. Прочитать сохранённый JSON обратно можно функцией json.load():

import json

with open("user.json", encoding="utf-8") as f:
    user = json.load(f)

print(user["name"], user["skills"])

Вывод:

Анна ['Python', 'SQL']

Дальше с user работают как с обычным словарём. Например, ключ, которого может не быть, безопасно достают через метод get().

Чем dump отличается от dumps в модуле json

У модуля две функции записи, и их постоянно путают. Разница в одной букве s от слова string: dumps() возвращает строку, а dump() пишет сразу в файл. С чтением та же история.

Функция Что делает Когда нужна
json.dump(obj, f) пишет JSON в открытый файл сохранить данные на диск
json.dumps(obj) возвращает JSON строкой отправить в API, вывести в лог, положить в базу
json.load(f) читает JSON из файла загрузить сохранённые данные
json.loads(s) разбирает JSON из строки обработать ответ сервера
import json

data = {"city": "Казань", "rooms": 2}

text = json.dumps(data, ensure_ascii=False)
print(type(text), text)

with open("flat.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False)

Вывод:

<class 'str'> {"city": "Казань", "rooms": 2}

Через dumps() тоже можно записать файл: получить строку и передать её в f.write(). Так делают, когда строку перед записью нужно проверить или изменить. В остальных случаях dump() короче.

CheckroiCheckroiПодборка курсов по API179 курсов • 37 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→ Канал основателя Checkroi Вани Буявца3 700 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединиться

Как записать JSON с отступами, кириллицей и сортировкой

По умолчанию модуль пишет JSON в одну строку и экранирует все символы вне ASCII. Машине так нормально, а человеку такой файл читать тяжело.

Поведение меняют четыре параметра. Они одинаково работают в dump() и dumps(), полный список есть в документации модуля json.

Параметр По умолчанию Что меняет
indent None, всё в одну строку число 2 или 4 даёт отступы и перенос строк
ensure_ascii True, кириллица кодами \uXXXX False оставляет буквы как есть
sort_keys False True сортирует ключи по алфавиту
separators (", ", ": "), а с indent (",", ": ") (",", ":") убирает все пробелы

Кириллица без кодов \u

Вот что делает ensure_ascii с городом «Казань»:

import json

data = {"city": "Казань", "rooms": 2}
print(json.dumps(data))
print(json.dumps(data, ensure_ascii=False))

Вывод:

{"city": "\u041a\u0430\u0437\u0430\u043d\u044c", "rooms": 2}
{"city": "Казань", "rooms": 2}

Оба варианта корректны, при чтении Python вернёт то же слово. Но в первом случае найти нужную запись глазами в редакторе уже не выйдет. Откуда берутся такие коды и чем Юникод отличается от UTF-8, мы объясняли в статье про кодировки и кракозябры.

Отступы, сортировка и JSON в одну строку

import json

order = {"id": 512, "items": ["чай", "сахар"], "paid": True}

print(json.dumps(order, ensure_ascii=False, indent=2, sort_keys=True))
print(json.dumps(order, ensure_ascii=False, separators=(",", ":")))

Вывод:

{
  "id": 512,
  "items": [
    "чай",
    "сахар"
  ],
  "paid": true
}
{"id":512,"items":["чай","сахар"],"paid":true}

Компактный вариант с separators=(",", ":") экономит место, когда JSON уходит по сети или копится в логах. Для конфигов и файлов, которые будут открывать люди, удобнее indent=2 или indent=4.

CheckroiCheckroiПодборка курсов по JSON46 курсов • 13 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Какие типы Python можно сохранить в JSON

В JSON есть только объекты, массивы, строки, числа, true, false и null. Модуль переводит типы Python в них по таблице:

Python JSON
dict объект {}
list, tuple массив []
str строка
int, float число
True, False true, false
None null

Две особенности этой таблицы ломают код уже после чтения файла:

  • Кортеж вернётся списком. Записали (3, 4), прочитали [3, 4]. Если дальше код проверяет тип, он сработает иначе.
  • Числовые ключи станут строками. В JSON ключ объекта всегда строка, поэтому {1: "один"} после записи и чтения превращается в {"1": "один"}, а обращение data[1] падает с KeyError.
import json

data = {1: "один", "point": (3, 4), "ok": False, "empty": None}
text = json.dumps(data, ensure_ascii=False)
print(text)
print(json.loads(text))

Вывод:

{"1": "один", "point": [3, 4], "ok": false, "empty": null}
{'1': 'один', 'point': [3, 4], 'ok': False, 'empty': None}

Документация модуля предупреждает об этом прямо: если в словаре были ключи не строкового типа, после loads(dumps(x)) он может не совпасть с исходным. Ключи из файла переводите обратно в числа сами: {int(k): v for k, v in data.items()}.

Как записать в JSON даты, множества и свои классы

Дата, множество и объект раскладываются по ячейкам JSON-структуры

Всё, чего нет в таблице выше, модуль записывать отказывается. Дата, множество, Decimal или объект своего класса дают одну и ту же ошибку:

TypeError: Object of type date is not JSON serializable

Функция в параметре default

Решение: передать в параметр default функцию, которая переведёт непонятный объект в понятный. Модуль вызывает её для каждого объекта, который не смог записать сам.

import json
from datetime import date, datetime
from decimal import Decimal

def to_json(obj):
    if isinstance(obj, (date, datetime)):
        return obj.isoformat()
    if isinstance(obj, set):
        return sorted(obj)
    if isinstance(obj, Decimal):
        return str(obj)
    raise TypeError(f"не знаю, как записать {type(obj).__name__}")

report = {
    "day": date(2026, 11, 2),
    "tags": {"python", "json"},
    "price": Decimal("1499.90"),
}

print(json.dumps(report, default=to_json, ensure_ascii=False))

Вывод:

{"day": "2026-11-02", "tags": ["json", "python"], "price": "1499.90"}

Последняя строка функции обязательна. Если тип не обработан и функция ничего не вернула, Python получит None и запишет в файл null вместо данных, без единой ошибки.

Множество мы записали через sorted(). У set нет порядка элементов, и без сортировки содержимое файла могло бы меняться от запуска к запуску. Цену из Decimal сохранили строкой, чтобы не потерять копейки на переводе во float.

Свои классы и dataclass

Объект своего класса проще всего сначала превратить в словарь. Для dataclass это делает функция asdict() из модуля dataclasses, а для обычного класса подойдёт свой метод, который собирает словарь из нужных атрибутов. Как устроены классы, объекты и атрибуты, мы разбирали в статье ООП простыми словами.

import json
from dataclasses import dataclass, asdict

@dataclass
class Student:
    name: str
    score: int

students = [Student("Анна", 92), Student("Борис", 78)]

with open("students.json", "w", encoding="utf-8") as f:
    json.dump([asdict(s) for s in students], f, ensure_ascii=False, indent=2)

Содержимое students.json:

[
  {
    "name": "Анна",
    "score": 92
  },
  {
    "name": "Борис",
    "score": 78
  }
]

Как дописать данные в существующий JSON-файл

Первое, что приходит в голову: открыть файл в режиме "a" и вызвать json.dump() ещё раз. Так не получится. Два объекта склеятся подряд, и файл перестанет быть валидным JSON.

import json

with open("log.json", "a", encoding="utf-8") as f:
    json.dump({"step": 1}, f)
with open("log.json", "a", encoding="utf-8") as f:
    json.dump({"step": 2}, f)

with open("log.json", encoding="utf-8") as f:
    json.load(f)

В файле окажется {"step": 1}{"step": 2}, а чтение упадёт:

json.decoder.JSONDecodeError: Extra data: line 1 column 12 (char 11)

В документации json.dump() об этом есть отдельное предупреждение: повторные вызовы dump() с одним и тем же файлом дают невалидный JSON-файл.

Прочитать, изменить, записать заново

Рабочий способ для небольших файлов: прочитать всё содержимое, добавить запись в Python и перезаписать файл целиком.

import json
from pathlib import Path

path = Path("tasks.json")

tasks = json.loads(path.read_text(encoding="utf-8")) if path.exists() else []
tasks.append({"title": "Сдать отчёт", "done": False})

path.write_text(json.dumps(tasks, ensure_ascii=False, indent=2), encoding="utf-8")
print(len(tasks))

Первый запуск создаст файл и напечатает 1, второй допишет ещё одну задачу и напечатает 2. Так хранят настройки и списки дел почти все небольшие программы, включая телеграм-ботов на Python.

Очистить JSON-файл можно тем же способом: записать в него пустой список или словарь, например json.dump([], f). Совсем пустой файл модуль потом не прочитает и выдаст JSONDecodeError: Expecting value.

JSON Lines для логов и больших объёмов

Если записи только добавляются, как в журнале событий, перечитывать весь файл ради одной строки накладно. Для такого случая есть формат JSON Lines: в каждой строке файла лежит отдельное JSON-значение, а строки разделены символом \n.

import json

events = [{"user": 1, "action": "login"}, {"user": 2, "action": "buy"}]

with open("events.jsonl", "a", encoding="utf-8") as f:
    for event in events:
        f.write(json.dumps(event, ensure_ascii=False) + "\n")

with open("events.jsonl", encoding="utf-8") as f:
    rows = [json.loads(line) for line in f]
print(rows)

Вывод:

[{'user': 1, 'action': 'login'}, {'user': 2, 'action': 'buy'}]

Режим "a" здесь безопасен: каждая строка читается отдельно. Если данные плоские, без вложенных списков и словарей, бывает удобнее формат CSV, его открывает и Excel.

Ваня БуявецКанал основателя Checkroi Вани БуявцаЗабирайте промпты и обучение по нейросетям в моём Телеграм-каналеБольше 3 700 человек уже применяют Claude Code, ChatGPT и другие нейросети в работе, учёбе, бизнесе и жизниПерейти в канал

Частые ошибки при записи JSON и как их исправить

Рой с улыбкой отмечает исправленные ошибки в чек-листе
  • Вместо букв в файле коды \u041a\u0430. Причина: по умолчанию ensure_ascii=True. Решение: передайте ensure_ascii=False и откройте файл с encoding="utf-8".
  • UnicodeEncodeError: 'charmap' codec can't encode character. Файл открыт без encoding, и Python взял кодировку системы. В Python 3.14 и раньше она зависит от платформы, на русской Windows это cp1251, где нет эмодзи и многих символов. С версии 3.15 по умолчанию работает UTF-8, так решили в PEP 686. Решение: пишите encoding="utf-8" явно, тогда код ведёт себя одинаково в любой версии.
  • TypeError: Object of type ... is not JSON serializable. В данных есть тип, которого нет в таблице выше. Решение: функция в default или перевод объекта в словарь до записи.
  • JSONDecodeError: Extra data при чтении. В файл несколько раз писали в режиме "a". Решение: перезаписывать файл целиком или перейти на JSON Lines.
  • В файле NaN, и другая программа его не читает. Python по умолчанию записывает NaN и Infinity, хотя стандарт JSON RFC 8259 такие значения не допускает. Решение: заменить их на None до записи или передать allow_nan=False, тогда модуль сразу поднимет ValueError.
  • Файл оказался пустым или обрезанным. Режим "w" стирает старое содержимое ещё при открытии. Если программа упадёт посреди dump(), в файле останется обрывок вроде {"a": 1, "day": . Решение: писать во временный файл и заменять им оригинал, пример ниже.

Защищённая запись умещается в короткую функцию. Временный файл создаётся в той же папке, а потом os.replace() подменяет им оригинал. Согласно документации os.replace(), успешное переименование атомарно, этого требует стандарт POSIX.

import json
import os
import tempfile

def save_json(data, path):
    folder = os.path.dirname(os.path.abspath(path))
    with tempfile.NamedTemporaryFile("w", encoding="utf-8", dir=folder,
                                     suffix=".tmp", delete=False) as tmp:
        json.dump(data, tmp, ensure_ascii=False, indent=2)
    os.replace(tmp.name, path)

save_json({"version": 2, "status": "готово"}, "settings.json")
print(open("settings.json", encoding="utf-8").read())

Вывод:

{
  "version": 2,
  "status": "готово"
}

Если запись сорвётся, старый settings.json останется целым. Такую функцию кладут в общий модуль проекта и вызывают вместо голого dump(), как любую свою функцию.

Где освоить Python системно

Запись JSON нужна почти в каждой рабочей задаче: настройки программ, ответы API, выгрузки для аналитики. Следом в программах обучения обычно идут запросы к API, базы данных и обработка исключений.

Если хочется пройти этот путь по программе с проверкой заданий, ниже курсы из нашего каталога. Сравнить их по цене, длительности и формату можно на странице курсов по Python, а понять, куда такие навыки ведут дальше, поможет обзор профессии Python-разработчика.

КурсШколаСтоимость со скидкойВ рассрочкуДлитель­ностьОбзор курса от Checkroi
Профессия «Python-разработчик»
Перейти на сайт курса
SkillboxSkillbox157 335 ₽5987 ₽/мес.10 месяцевОбзор курса
Fullstack-разработчик на Python
Перейти на сайт курса
НетологияНетология137 000 ₽7125 ₽/мес.21 месяцОбзор курса
ДО Профессия Python-разработчик
Перейти на сайт курса
GeekBrainsGeekBrains149 001 ₽3167 ₽/мес.10 месяцевОбзор курса
Автоматизированное тестирование на Python
Перейти на сайт курса
SkillboxSkillbox122 226 ₽4108 ₽/мес.9 месяцевОбзор курса
Профессия Python-разработчик
Перейти на сайт курса
SkillFactorySkillFactory140 040 ₽3890 ₽/мес.10 месяцевОбзор курса

Больше программ — в полном каталоге курсов по Python

Часто задаваемые вопросы

Как создать JSON-файл в Python?

Откройте файл на запись и вызовите json.dump(): with open("data.json", "w", encoding="utf-8") as f: json.dump(data, f). Если файла нет, Python создаст его сам, если есть, перезапишет целиком.

Как сохранить кириллицу в JSON без кодов \u?

Передайте в json.dump() параметр ensure_ascii=False и откройте файл с encoding="utf-8". Тогда «Казань» останется буквами, а не превратится в \u041a\u0430\u0437\u0430\u043d\u044c.

Чем json.dump отличается от json.dumps?

json.dump() пишет JSON сразу в открытый файл, а json.dumps() возвращает его строкой. Строка нужна, когда данные уходят в API, лог или базу, а не на диск.

Как дописать данные в существующий JSON-файл?

Прочитайте файл через json.load(), добавьте запись в список или словарь и перезапишите файл целиком. Повторный json.dump() в режиме «a» склеит объекты, и файл станет невалидным. Для журналов, куда записи только добавляются, удобнее формат JSON Lines.

Как записать в JSON дату или datetime?

Передайте в json.dump() параметр default с функцией, которая возвращает obj.isoformat(). Без неё модуль выдаст TypeError: Object of type date is not JSON serializable.

Как записать JSON в одну строку без пробелов?

Не передавайте indent и укажите separators=(",", ":"). Получится самая компактная запись вида {"id":512,"paid":true}.

Читайте Checkroi первым в Google
Добавьте Checkroi в избранные источники — и наши разборы курсов и обзоры школ будут показываться выше в вашей выдаче Google.
Оставить комментарий
0 комментариев
Форма комментария

Оставьте комментарий

Напишите, что думаете. Нам важно ваше мнение!