JSON в Python: чтение и запись файлов, json.load/json.dump — практическое руководство

JSON в Python: чтение и запись файлов, json.load/json.dump — практическое руководство

JSON в Python: чтение и запись файлов, json.load/json.dump — практическое руководство

JSON — дефолтный формат обмена данными между сервисами и фронтендом. В Python для работы с ним есть стандартный модуль json: лёгкий, быстрый и удобный. В этом руководстве вы узнаете, как читать и записывать JSON-файлы, работать со строками, управлять форматированием, обрабатывать большие логи в формате JSON Lines и сериализовать нестандартные типы данных.

Что такое JSON и где он используется

JSON (JavaScript Object Notation) — текстовый формат представления структурированных данных. Его используют API, мобильные приложения, сервисы логирования и аналитики. Ключевые преимущества: человекочитаемость, компактность и поддержка во всех языках программирования, включая Python.

Быстрый старт: чтение и запись файлов JSON (json.load, json.dump)

Самые частые операции — загрузить JSON из файла в Python-объекты (dict, list) и сохранить обратно.

import json
from pathlib import Path

path = Path("data/users.json")

# Чтение JSON из файла
with path.open(encoding="utf-8") as f:
    users = json.load(f)  # list[dict] или dict — зависит от структуры файла

# Изменение данных в памяти
users.append({"id": 3, "name": "Ирина", "active": True})

# Запись JSON в файл (красиво отформатированный, с кириллицей)
with path.open("w", encoding="utf-8") as f:
    json.dump(users, f, ensure_ascii=False, indent=2)

Обратите внимание на параметры:

  • encoding=»utf-8″ — избегает проблем с кодировкой;
  • ensure_ascii=False — сохраняет кириллицу, а не uXXXX-последовательности;
  • indent=2 — читабельный формат для диффов и ревью.
  • Строки: json.loads и json.dumps

    Когда данные приходят по сети или из БД как текст, используйте функции для строк:

    import json
    from decimal import Decimal
    
    text = '{"price": 12.50, "tags": ["sale", "promo"]}'
    
    # Преобразуем строку JSON в объекты Python
    # parse_float=Decimal — чтобы не потерять точность в деньгах
    data = json.loads(text, parse_float=Decimal)
    
    # Обратно в строку (компактный вид без лишних пробелов)
    packed = json.dumps(data, ensure_ascii=False, separators=(",", ":"))
    print(packed)  # {"price":12.50,"tags":["sale","promo"]}
    

    Форматирование: компактный vs читаемый JSON

    Для хранения и передачи по сети чаще нужен компактный JSON, а для ревью — читаемый.

    import json
    
    # Компактный вариант (минимум байт)
    compact = json.dumps({"a": 1, "b": [1, 2, 3]}, ensure_ascii=False, separators=(",", ":"))
    
    # Красивый вывод (ключи отсортированы для стабильных диффов)
    pretty = json.dumps({"b": [1, 2, 3], "a": 1}, ensure_ascii=False, indent=2, sort_keys=True)
    
    print(compact)
    print(pretty)
    
  • separators=(«,», «:») — убирает пробелы после запятых и двоеточий;
  • sort_keys=True — одинаковый порядок ключей облегчает сравнение файлов в git.
  • Большие данные: JSON Lines (NDJSON)

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

    import json
    
    # Запись NDJSON
    with open("events.jsonl", "w", encoding="utf-8") as f:
        for i in range(3):
            row = {"event": "click", "i": i}
            f.write(json.dumps(row, ensure_ascii=False) + "n")
    
    # Чтение NDJSON (строка за строкой)
    events = []
    with open("events.jsonl", encoding="utf-8") as f:
        for line in f:
            if line.strip():  # пропускаем пустые строки
                events.append(json.loads(line))
    
    print(events)
    

    Плюсы NDJSON: потоковая обработка, меньшая пиковая память, лёгкая конкатенация файлов. Минус: это не единый JSON-объект, а набор отдельных записей по строкам.

    Кастомная сериализация: datetime, Decimal и другие типы

    Стандартный json умеет сериализовать только базовые типы (dict, list, str, int, float, bool, None). Для нестандартных добавляем default-функцию.

    import json
    from datetime import datetime
    from decimal import Decimal
    
    def to_json(obj):
        if isinstance(obj, datetime):
            return obj.isoformat()  # "2025-01-15T10:30:00"
        if isinstance(obj, Decimal):
            return float(obj)  # или str(obj), если нужна точность при передаче
        raise TypeError(f"Type {type(obj)} is not JSON serializable")
    
    order = {
        "id": 101,
        "total": Decimal("19.90"),
        "created_at": datetime(2025, 1, 15, 10, 30),
    }
    
    text = json.dumps(order, default=to_json, ensure_ascii=False, indent=2)
    print(text)
    

    А чтобы преобразовывать значения при загрузке, используйте object_hook — она вызывается для каждого dict.

    import json
    from datetime import datetime
    
    # Предположим, у нас есть JSON из примера выше в переменной text
    
    def parse_datetime(d):
        for k, v in list(d.items()):
            if k.endswith("_at") and isinstance(v, str):
                try:
                    d[k] = datetime.fromisoformat(v)
                except ValueError:
                    pass
        return d
    
    restored = json.loads(text, object_hook=parse_datetime)
    print(type(restored["created_at"]))  # <class 'datetime.datetime'>
    

    Безопасность и надёжность

  • Никогда не используйте eval для разбора JSON — только json.loads/json.load.
  • Проверяйте размеры входных данных, если читаете из внешних источников (ограничивайте upload size, применяйте таймауты на уровне транспорта).
  • Указывайте encoding=»utf-8″ при работе с файлами — меньше сюрпризов на проде.
  • Логируйте ошибки парсинга с деталями позиции — это ускоряет отладку.
  • Частые ошибки и как их избежать

  • Одинарные кавычки и лишние запятые — это не JSON. Разрешены только двойные кавычки, запятая после последнего элемента запрещена.
  • Путаете функции: dump/load — для файлов, dumps/loads — для строк.
  • Теряете кириллицу, видите u041F… — включите ensure_ascii=False и правильную кодировку файла.
  • Денежные суммы на float — лучше используйте Decimal (parse_float=Decimal) или храните в копейках как int.
  • import json
    
    bad = "{'a':1,}"  # одинарные кавычки и лишняя запятая — это НЕ JSON
    try:
        json.loads(bad)
    except json.JSONDecodeError as e:
        print(f"Ошибка JSON: {e}")
    

    Мини-практика: маленький конвертер с фильтрацией

    Пример: читаем массив объектов из файла, фильтруем активных пользователей и сохраняем компактный JSON для API.

    import json
    from pathlib import Path
    
    src = Path("data/users.json")
    dst = Path("build/active_users.json")
    
    dst.parent.mkdir(parents=True, exist_ok=True)
    
    with src.open(encoding="utf-8") as f:
        users = json.load(f)
    
    active = [u for u in users if u.get("active") is True]
    
    with dst.open("w", encoding="utf-8") as f:
        json.dump(active, f, ensure_ascii=False, separators=(",", ":"))
    
    print(f"Сохранено: {dst} — {len(active)} записей")
    

    Чеклист лучших практик JSON в Python

  • Для файлов: json.load/json.dump и encoding=»utf-8″.
  • Для строк: json.loads/json.dumps.
  • Для продакшена: compact JSON (separators), для ревью — indent и sort_keys.
  • Русский текст: ensure_ascii=False.
  • Деньги: Decimal или int-центы; при сериализации используйте default.
  • Большие потоки: JSON Lines (строка = запись).
  • Пользовательские типы: default и object_hook.
  • Валидируйте входные данные и обрабатывайте JSONDecodeError.
  • Куда двигаться дальше

    Освоив базовые операции с JSON, вы готовы к API-клиентам, интеграциям и обработке логов. Если хотите системно прокачать Python с практикой и проектами — присмотритесь к курсу: Прокачать Python с нуля до гуру на реальных задачах →.

    Теперь у вас под рукой удобный рецепт: как читать и записывать JSON в Python, красиво форматировать данные, работать с большими файлами и сериализовать сложные типы. Пользуйтесь и экономьте часы на рутине!

    Источник

    НЕТ КОММЕНТАРИЕВ

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