Как организовать возврат JSON в Python функциях

Раздел: Функции -> Форматы данных: JSON

Основное эффективное решение: стандартный модуль json

Как вернуть JSON из обычной функции, не подключая веб-фреймворки?

Наиболее универсальный способ - использовать встроенный модуль json. Функция принимает данные (словарь, список, кортеж) и возвращает строку в формате JSON с помощью json.dumps(). При необходимости можно задать параметры форматирования, сортировки ключей, кодировки.

import json

def get_user_profile(user_id):
    profile = {
        "id": user_id,
        "name": "Анна",
        "age": 30,
        "email": "anna@example.com",
        "active": True
    }
    return json.dumps(profile, ensure_ascii=False, indent=2)

result = get_user_profile(101)
print(result)
print(type(result))

Json open python (открытие json файла в python)

{
  "id": 101,
  "name": "Анна",
  "age": 30,
  "email": "anna@example.com",
  "active": true
}
<class 'str'>

преобразовать json в словарь python (преобразование json в словарь python)

Почему стоит использовать ensure_ascii=False?

Параметр сохраняет кириллицу и другие не-ASCII символы в читаемом виде, иначе они будут преобразованы в escape-последовательности. Параметр indent добавляет отступы для читаемости.

Типичная ошибка: сериализация объекта datetime

Прямая передача объекта datetime в json.dumps() вызывает TypeError: Object of type datetime is not JSON serializable. Решение - передать собственный обработчик через параметр default или преобразовать дату в строку заранее.

from datetime import datetime
def json_serial(obj):
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError(f"Тип {type(obj)} не поддерживается")

def get_event(event_id):
    event = {
        "id": event_id,
        "created_at": datetime.now()
    }
    return json.dumps(event, default=json_serial, ensure_ascii=False, indent=2)

сохранить json python (сохранение json в файл python)

Варианты возврата JSON

Как сделать возврат словаря, а сериализацию выполнять вне функции?

Иногда функция возвращает готовый словарь, а преобразование в JSON происходит в вызывающем коде. Это удобно для тестирования и повторного использования данных.

def get_config():
    return {
        "debug": True,
        "port": 8080,
        "allowed_hosts": ["localhost", "127.0.0.1"]
    }

# вне функции
import json
config_json = json.dumps(get_config(), indent=2)
print(config_json)

Python формат даты (формат даты и времени в python)

Как использовать библиотеку orjson для более быстрой сериализации?

Библиотека orjson (ORJSON) сериализует данные значительно быстрее стандартного модуля и автоматически обрабатывает многие типы, включая datetime и UUID.

import orjson
def get_fast_data():
    data = {"value": 42, "uuid": "550e8400-e29b-41d4-a716-446655440000"}
    return orjson.dumps(data).decode('utf-8')

print(get_fast_data())

Python json get (получение данных из json в python)

{"value":42,"uuid":"550e8400-e29b-41d4-a716-446655440000"}

Python 3 json (работа с json в python 3)

Проблема: несериализуемые типы (set, bytes)

Множества set не могут быть напрямую преобразованы в JSON. Необходимо сначала преобразовать их в список.

def get_permissions():
    perms = {"read", "write", "execute"}
    return json.dumps(list(perms), ensure_ascii=False)

Python json lib (библиотека json в python)

Для bytes нужно декодировать в строку или использовать base64.

Как вернуть JSON, используя dataclasses?

Модуль dataclasses позволяет объявить классы с атрибутами, а затем сериализовать экземпляр с помощью json.dumps() и параметра default или через __dict__.

from dataclasses import dataclass, asdict
import json

@dataclass
class Product:
    name: str
    price: float
    available: bool

def get_product(product_id):
    prod = Product("Ноутбук", 899.99, True)
    return json.dumps(asdict(prod), ensure_ascii=False, indent=2)

print(get_product(1))

вложенный json python (вложенный json в python)

{
  "name": "Ноутбук",
  "price": 899.99,
  "available": true
}

Json lines python (формат json lines в python)

Как вернуть JSON с вложенными структурами и пустыми значениями?

Параметр default помогает обрабатывать None, пользовательские объекты. Для пропусков или пустых полей можно использовать skipkeys или предварительную обработку.

def get_order(order_id):
    order = {
        "id": order_id,
        "items": [
            {"product": "Книга", "quantity": 2},
            None
        ],
        "address": None
    }
    return json.dumps(order, indent=2, default=lambda x: "недоступно" if x is None else str(x))

print(get_order(45))

Расширенные примеры возврата JSON

Пример 1: Возврат JSON через веб-фреймворк FastAPI

В FastAPI функция-обработчик возвращает словарь или Pydantic модель, а JSON генерируется автоматически.

Пример
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float

@app.get("/item/{item_id}")
def read_item(item_id: int):
    item = Item(name="Клавиатура", price=2500.0)
    return {"item_id": item_id, "data": item}

# Запрос: /item/7
# Ответ: {"item_id":7,"data":{"name":"Клавиатура","price":2500.0}}
{"item_id":7,"data":{"name":"Клавиатура","price":2500.0}}

FastAPI использует Pydantic для валидации и сериализации. Возвращается не строка, а объект, который автоматически преобразуется в JSON-ответ.

Пример 2: Кастомный сериализатор для сложных объектов

Если требуется часто сериализовать объекты одного класса, удобно определить метод to_json.

Пример
import json
from typing import Any

class Person:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age
    
    def to_json(self) -> str:
        return json.dumps({
            "name": self.name,
            "age": self.age,
            "type": "Person"
        }, ensure_ascii=False)

def create_person() -> str:
    p = Person("Мария", 28)
    return p.to_json()

print(create_person())
{"name": "Мария", "age": 28, "type": "Person"}

Пример 3: Использование генераторов для построчного вывода JSON

При работе с большими данными можно вернуть JSON построчно, используя генератор и библиотеку ijson или простую конкатенацию. Однако стандартный подход - вернуть полную строку; для стриминга лучше использовать веб-фреймворки.

Пример
import json

def stream_large_json():
    data = [{"id": i, "value": i**2} for i in range(5)]
    # Имитация потоковой передачи
    yield '['
    for idx, item in enumerate(data):
        if idx > 0:
            yield ','
        yield json.dumps(item)
    yield ']'

result = ''.join(stream_large_json())
print(result)
[{"id": 0, "value": 0},{"id": 1, "value": 1},{"id": 2, "value": 4},{"id": 3, "value": 9},{"id": 4, "value": 16}]

Пример 4: Ручное формирование JSON с экранированием

Иногда нужно вставить данные с кавычками или спецсимволами, не используя модуль json. Это опасно, но демонстрирует принцип.

Пример
def unsafe_json(key, value):
    import json
    # Лучше использовать json.dumps, но для примера:
    escaped_value = value.replace('"', '\\"')
    return f'{{"{key}": "{escaped_value}"}}'

print(unsafe_json("text", 'строка с "кавычками"'))
# Правильная сериализация через json.dumps гарантирует безопасность.
{"text": "строка с \"кавычками\""}

Проблема: циклические ссылки

Если объект содержит ссылку на самого себя, json.dumps() выдаст ошибку. Решение - использовать параметр check_circular=False (не рекомендуется) или удалить цикл вручную.

Пример
class Node:
    def __init__(self, name):
        self.name = name
        self.parent = None

def get_circular_data():
    a = Node("A")
    b = Node("B")
    a.parent = b
    b.parent = a  # циклическая ссылка
    try:
        return json.dumps({"a": a.__dict__, "b": b.__dict__})
    except Exception as e:
        return str(e)

print(get_circular_data())
'TypeError: Object of type Node is not JSON serializable'

Даже если преобразовать через __dict__, циклическая ссылка останется. Необходимо разорвать круг перед сериализацией.

Пример 5: Работа с Decimal и другими числовыми типами

Тип Decimal из модуля decimal не сериализуется по умолчанию. Можно преобразовать в float (с потерей точности) или в строку.

Пример
from decimal import Decimal
import json

def get_price():
    price = Decimal('19.99')
    # Вариант 1: float
    return json.dumps({"price": float(price)})
    # Вариант 2: строка
    # return json.dumps({"price": str(price)})

print(get_price())
{"price": 19.99}

Для точной передачи рекомендуется сохранять цену как строку, особенно в финансовых приложениях.

Возврат JSON из функции Python - comments

En
Python return json (python)