← Вернуться к блогу

Python и JSON: Полное руководство по работе с данными

Исчерпывающее руководство по работе с JSON в Python: парсинг, сериализация, обработка ошибок, продвинутые техники и best practices.

Big JSON Team15 мин чтенияprogramming
B

Big JSON Team

Technical Writer

Expert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.

15 мин чтения

# Python и JSON: Полное руководство по работе с данными

Python предоставляет мощные встроенные инструменты для работы с JSON. В этом подробном руководстве мы рассмотрим все аспекты работы с JSON в Python: от базового парсинга до продвинутых техник обработки данных.

Модуль json в Python

Python включает встроенный модуль json для работы с JSON данными.

Импорт модуля

import json

Основные функции

  • json.dumps() — Python объект → JSON строка (сериализация)
  • json.dump() — Python объект → JSON файл
  • json.loads() — JSON строка → Python объект (десериализация)
  • json.load() — JSON файл → Python объект

Парсинг JSON

Из строки (json.loads)

import json

# JSON строка

json_string = '{"имя": "Иван", "возраст": 30, "город": "Москва"}'

# Парсинг в Python словарь

данные = json.loads(json_string)

print(данные) # {'имя': 'Иван', 'возраст': 30, 'город': 'Москва'}

print(type(данные)) # <class 'dict'>

print(данные['имя']) # Иван

Из файла (json.load)

import json

# Чтение JSON из файла

with open('data.json', 'r', encoding='utf-8') as file:

данные = json.load(file)

print(данные)

Пример файла data.json:
{

"пользователь": {

"имя": "Анна Иванова",

"email": "anna@example.com",

"возраст": 28

},

"настройки": {

"тема": "темная",

"язык": "ru"

}

}

Работа с данными:
print(данные['пользователь']['имя'])  # Анна Иванова

print(данные['настройки']['тема']) # темная

Сериализация в JSON

В строку (json.dumps)

import json

# Python словарь

пользователь = {

"имя": "Петр Сидоров",

"возраст": 35,

"город": "Санкт-Петербург",

"активен": True,

"баланс": None

}

# Сериализация в JSON строку

json_string = json.dumps(пользователь, ensure_ascii=False, indent=2)

print(json_string)

Результат:
{

"имя": "Петр Сидоров",

"возраст": 35,

"город": "Санкт-Петербург",

"активен": true,

"баланс": null

}

В файл (json.dump)

import json

данные = {

"компания": "ТехноСофт",

"сотрудники": [

{"имя": "Иван", "должность": "Разработчик"},

{"имя": "Мария", "должность": "Дизайнер"}

]

}

# Запись в файл

with open('output.json', 'w', encoding='utf-8') as file:

json.dump(данные, file, ensure_ascii=False, indent=2)

print("Данные сохранены в output.json")

Соответствие типов данных

Python → JSON

| Python | JSON |

|--------|------|

| dict | object |

| list, tuple | array |

| str | string |

| int, float | number |

| True | true |

| False | false |

| None | null |

Пример:
python_data = {

"строка": "текст",

"число": 42,

"дробное": 3.14,

"булево": True,

"null": None,

"массив": [1, 2, 3],

"объект": {"ключ": "значение"}

}

json_string = json.dumps(python_data)

print(json_string)

# {"строка": "текст", "число": 42, "дробное": 3.14, "булево": true, "null": null, "массив": [1, 2, 3], "объект": {"ключ": "значение"}}

JSON → Python

json_string = '''

{

"string": "текст",

"number": 42,

"float": 3.14,

"boolean": true,

"null": null,

"array": [1, 2, 3],

"object": {"key": "value"}

}

'''

python_data = json.loads(json_string)

print(type(python_data)) # <class 'dict'>

print(type(python_data['array'])) # <class 'list'>

print(type(python_data['boolean'])) # <class 'bool'>

print(type(python_data['null'])) # <class 'NoneType'>

Параметры форматирования

ensure_ascii

По умолчанию True — экранирует non-ASCII символы:

данные = {"имя": "Иван", "город": "Москва"}

# С ensure_ascii=True (по умолчанию)

print(json.dumps(данные))

# {"\u0438\u043c\u044f": "\u0418\u0432\u0430\u043d", "\u0433\u043e\u0440\u043e\u0434": "\u041c\u043e\u0441\u043a\u0432\u0430"}

# С ensure_ascii=False (для кириллицы)

print(json.dumps(данные, ensure_ascii=False))

# {"имя": "Иван", "город": "Москва"}

indent

Форматирование с отступами:

данные = {"имя": "Иван", "навыки": ["Python", "JavaScript"]}

# Без отступов (компактно)

print(json.dumps(данные, ensure_ascii=False))

# {"имя": "Иван", "навыки": ["Python", "JavaScript"]}

# С отступами

print(json.dumps(данные, ensure_ascii=False, indent=2))

Результат:
{

"имя": "Иван",

"навыки": [

"Python",

"JavaScript"

]

}

sort_keys

Сортировка ключей:

данные = {"имя": "Иван", "возраст": 30, "город": "Москва"}

# Без сортировки

print(json.dumps(данные, ensure_ascii=False, indent=2))

# С сортировкой

print(json.dumps(данные, ensure_ascii=False, indent=2, sort_keys=True))

С сортировкой:
{

"возраст": 30,

"город": "Москва",

"имя": "Иван"

}

separators

Настройка разделителей:

данные = {"a": 1, "b": 2}

# По умолчанию

print(json.dumps(данные)) # {"a": 1, "b": 2}

# Компактный формат

print(json.dumps(данные, separators=(',', ':'))) # {"a":1,"b":2}

# С пробелами

print(json.dumps(данные, separators=(', ', ': '))) # {"a": 1, "b": 2}

Обработка ошибок

JSONDecodeError

import json

неправильный_json = '{"имя": "Иван", "возраст": 30,}' # Висячая запятая

try:

данные = json.loads(неправильный_json)

except json.JSONDecodeError as e:

print(f"Ошибка парсинга JSON: {e}")

print(f"Строка: {e.lineno}, Колонка: {e.colno}")

print(f"Позиция: {e.pos}")

Вывод:
Ошибка парсинга JSON: Expecting property name enclosed in double quotes: line 1 column 32 (char 31)

Строка: 1, Колонка: 32

Позиция: 31

Безопасный парсинг

def безопасный_парсинг(json_string):

"""Безопасный парсинг JSON с обработкой ошибок"""

try:

return json.loads(json_string), None

except json.JSONDecodeError as e:

return None, f"Ошибка: {e}"

except Exception as e:

return None, f"Неожиданная ошибка: {e}"

# Использование

данные, ошибка = безопасный_парсинг('{"имя": "Иван"}')

if ошибка:

print(ошибка)

else:

print(данные)

Работа с пользовательскими классами

Сериализация классов

import json

from datetime import datetime

class Пользователь:

def __init__(self, имя, возраст, email):

self.имя = имя

self.возраст = возраст

self.email = email

self.создан = datetime.now()

def to_dict(self):

"""Конвертация в словарь"""

return {

"имя": self.имя,

"возраст": self.возраст,

"email": self.email,

"создан": self.создан.isoformat()

}

# Создание объекта

пользователь = Пользователь("Иван", 30, "ivan@example.com")

# Сериализация

json_string = json.dumps(пользователь.to_dict(), ensure_ascii=False, indent=2)

print(json_string)

Кастомный JSONEncoder

import json

from datetime import datetime

from decimal import Decimal

class РасширенныйEncoder(json.JSONEncoder):

"""Кастомный encoder для специальных типов"""

def default(self, obj):

if isinstance(obj, datetime):

return obj.isoformat()

elif isinstance(obj, Decimal):

return float(obj)

elif isinstance(obj, set):

return list(obj)

elif hasattr(obj, 'to_dict'):

return obj.to_dict()

return super().default(obj)

# Использование

данные = {

"дата": datetime.now(),

"цена": Decimal("99.99"),

"теги": {"python", "json", "tutorial"},

"пользователь": пользователь

}

json_string = json.dumps(

данные,

cls=РасширенныйEncoder,

ensure_ascii=False,

indent=2

)

print(json_string)

Десериализация в классы

def dict_to_user(data):

"""Конвертация словаря в объект Пользователь"""

return Пользователь(

имя=data['имя'],

возраст=data['возраст'],

email=data['email']

)

# Парсинг

json_string = '{"имя": "Мария", "возраст": 25, "email": "maria@example.com"}'

данные = json.loads(json_string)

пользователь = dict_to_user(данные)

print(f"Имя: {пользователь.имя}, Возраст: {пользователь.возраст}")

Работа с большими JSON файлами

Streaming парсинг

import json

def обработать_большой_файл(filename):

"""Обработка большого JSON файла построчно"""

with open(filename, 'r', encoding='utf-8') as file:

# Если JSON это массив объектов

data = json.load(file)

for item in data:

# Обработка каждого элемента

обработать_элемент(item)

def обработать_элемент(item):

# Ваша логика обработки

print(f"Обработка: {item}")

ijson для streaming

import ijson

def streaming_парсинг(filename):

"""Streaming парсинг с ijson"""

with open(filename, 'rb') as file:

parser = ijson.items(file, 'item')

for item in parser:

# Обработка без загрузки всего файла в память

print(item)

Chunked чтение

def читать_частями(filename, chunk_size=1000):

"""Чтение JSON массива частями"""

with open(filename, 'r', encoding='utf-8') as file:

data = json.load(file)

for i in range(0, len(data), chunk_size):

chunk = data[i:i + chunk_size]

yield chunk

# Использование

for chunk in читать_частями('large_data.json'):

print(f"Обработка {len(chunk)} элементов")

# Обработка chunk

Валидация JSON

Базовая валидация

def валидировать_json(json_string):

"""Проверка валидности JSON"""

try:

json.loads(json_string)

return True, "JSON валиден"

except json.JSONDecodeError as e:

return False, f"Ошибка: {e}"

# Тестирование

валидный = '{"имя": "Иван"}'

невалидный = '{"имя": Иван}'

print(валидировать_json(валидный)) # (True, 'JSON валиден')

print(валидировать_json(невалидный)) # (False, 'Ошибка: ...')

С JSON Schema

import json

import jsonschema

from jsonschema import validate

# Определение схемы

схема = {

"type": "object",

"properties": {

"имя": {"type": "string", "minLength": 1},

"возраст": {"type": "integer", "minimum": 0, "maximum": 150},

"email": {"type": "string", "format": "email"}

},

"required": ["имя", "возраст"]

}

# Валидация данных

def валидировать_по_схеме(данные, схема):

try:

validate(instance=данные, schema=схема)

return True, "Данные соответствуют схеме"

except jsonschema.exceptions.ValidationError as e:

return False, f"Ошибка валидации: {e.message}"

# Тестирование

данные = {

"имя": "Иван",

"возраст": 30,

"email": "ivan@example.com"

}

результат, сообщение = валидировать_по_схеме(данные, схема)

print(сообщение)

Работа с API

GET запрос

import requests

import json

def получить_пользователей():

"""Получение данных из API"""

response = requests.get('https://api.example.com/users')

# Проверка статуса

response.raise_for_status()

# Автоматический парсинг JSON

данные = response.json()

return данные

# Использование

try:

пользователи = получить_пользователей()

for пользователь in пользователи:

print(f"{пользователь['имя']}: {пользователь['email']}")

except requests.exceptions.RequestException as e:

print(f"Ошибка запроса: {e}")

POST запрос

def создать_пользователя(имя, email):

"""Отправка данных в API"""

url = 'https://api.example.com/users'

данные = {

"имя": имя,

"email": email,

"активен": True

}

response = requests.post(

url,

json=данные, # Автоматическая сериализация в JSON

headers={'Content-Type': 'application/json'}

)

response.raise_for_status()

return response.json()

# Использование

новый_пользователь = создать_пользователя("Анна", "anna@example.com")

print(f"Создан пользователь с ID: {новый_пользователь['id']}")

Продвинутые техники

Pretty printing

import json

def красивый_вывод(данные):

"""Красивый вывод JSON в консоль"""

print(json.dumps(данные, ensure_ascii=False, indent=2, sort_keys=True))

данные = {

"пользователи": [

{"имя": "Иван", "возраст": 30},

{"имя": "Мария", "возраст": 25}

]

}

красивый_вывод(данные)

Рекурсивная обработка

def рекурсивная_обработка(obj, функция):

"""Рекурсивное применение функции ко всем строкам"""

if isinstance(obj, dict):

return {k: рекурсивная_обработка(v, функция) for k, v in obj.items()}

elif isinstance(obj, list):

return [рекурсивная_обработка(item, функция) for item in obj]

elif isinstance(obj, str):

return функция(obj)

return obj

# Пример: перевод всех строк в верхний регистр

данные = {

"имя": "иван",

"навыки": ["python", "javascript"],

"адрес": {"город": "москва"}

}

результат = рекурсивная_обработка(данные, str.upper)

print(json.dumps(результат, ensure_ascii=False, indent=2))

Фильтрация данных

def фильтровать_ключи(данные, разрешенные_ключи):

"""Фильтрация данных по разрешенным ключам"""

if isinstance(данные, dict):

return {

k: фильтровать_ключи(v, разрешенные_ключи)

for k, v in данные.items()

if k in разрешенные_ключи

}

elif isinstance(данные, list):

return [фильтровать_ключи(item, разрешенные_ключи) for item in данные]

return данные

# Пример

пользователь = {

"имя": "Иван",

"email": "ivan@example.com",

"пароль": "secret", # Должен быть удален

"возраст": 30

}

безопасные_данные = фильтровать_ключи(

пользователь,

{"имя", "email", "возраст"}

)

print(json.dumps(безопасные_данные, ensure_ascii=False, indent=2))

Best Practices

1. Всегда используйте encoding='utf-8'

# Правильно

with open('data.json', 'r', encoding='utf-8') as f:

данные = json.load(f)

# Может вызвать проблемы с кириллицей

with open('data.json', 'r') as f: # Плохо

данные = json.load(f)

2. Используйте ensure_ascii=False для кириллицы

# Правильно для русского текста

json.dumps(данные, ensure_ascii=False)

# Создаст \\uXXXX для кириллицы

json.dumps(данные) # ensure_ascii=True по умолчанию

3. Обрабатывайте ошибки

try:

with open('data.json', 'r', encoding='utf-8') as f:

данные = json.load(f)

except FileNotFoundError:

print("Файл не найден")

except json.JSONDecodeError as e:

print(f"Ошибка парсинга: {e}")

except Exception as e:

print(f"Неожиданная ошибка: {e}")

4. Используйте context managers

# Правильно — файл автоматически закроется

with open('data.json', 'r', encoding='utf-8') as f:

данные = json.load(f)

# Плохо — нужно явно закрывать

f = open('data.json', 'r', encoding='utf-8')

данные = json.load(f)

f.close()

5. Валидируйте внешние данные

def обработать_api_ответ(json_string):

try:

данные = json.loads(json_string)

# Валидация структуры

if not isinstance(данные, dict):

raise ValueError("Ожидается объект")

if 'status' not in данные:

raise ValueError("Отсутствует поле status")

return данные

except (json.JSONDecodeError, ValueError) as e:

print(f"Ошибка: {e}")

return None

Заключение

Python предоставляет мощные и удобные инструменты для работы с JSON. Модуль json покрывает большинство потребностей, а для специальных случаев доступны дополнительные библиотеки.

Ключевые моменты:
  • Используйте json.loads() и json.dumps() для строк
  • Используйте json.load() и json.dump() для файлов
  • Всегда указывайте encoding='utf-8' и ensure_ascii=False
  • Обрабатывайте исключения JSONDecodeError
  • Используйте кастомные encoders для специальных типов
  • Для больших файлов применяйте streaming

С этим руководством вы готовы эффективно работать с JSON в Python!

Share:

Похожие статьи

Read in English