JSON в Python (Часть 1)

Обмен данными – важный компонент любого языка программирования. По сути, любая программа – это информация, которая поступает на вход и выдается на выход и может храниться  в определенных местах, которые называются базами данных.

JSON – это главный стандарт обмена информацией, ставший очень популярным фактически как он появился. Он нужен для перемещения данных из одного места в другое наряду с другими инструментами, такими как API. Также информация нередко хранится в документной базе данных. В любом случае, JSON – это важный аспект разработки приложений, и сегодня рассмотрим его более подробно.

JSON – что это такое?

JSON – это аббревиатура, которая расшифровывается как JavaScript Object Notation. Этот стандарт был взят из подмножества JavaScript, которое активно используется в веб-разработке. И разрабатывался на его основе. 

В любом случае уже сейчас JSON совместим с любым языком разработки приложений, поэтому о JavaScript мы упомянули исключительно в контексте истории.

В любом случае, подавляющее количество людей приняли JSON благодаря легкости как для компьютеров, так и для разработчиков.

Если говорить о JSON, этот стандарт сопряжен с огромным количеством преимуществ:

  1. Высокая компактность. 
  2. Читабельность как для компьютера, так и для человека.
  3. Совместимость с почти любым языком программирования. Очень полезно в случае, если приложение создается сразу с использованием нескольких языков разработки.

Когда может использоваться JSON? Например, если необходимо отправить определенную информацию к серверу и получить ее от него.

Структура JSON

Итак, давайте рассмотрим реальный пример JSON. Этот стандарт легок в понимании для каждого языка группы C. А поскольку Python – это C-язык, то вы тоже должны понять его структуру. 

{
    "firstName": "Jane",
    "lastName": "Doe",
    "hobbies": ["running", "sky diving", "singing"],
    "age": 35,
    "children": [
        {
            "firstName": "Alice",
            "age": 6
        },
        {
            "firstName": "Bob",
            "age": 8
        }
    ]
}

Python и JSON

Хорошо, а как реализовать JSON в Python? Требуется ли отдельный модуль для этого? Нет. Он уже содержит модуль json, с помощью которого можно выполнять кодирование и декодирование сведений, представленных в JSON.

Модуль – это компонент языка, который позволяет одним махом подключить целый комплекс функций, методов и объектов для реализации тех или иных задач. Так, модуль JSON позволяет реализовать на практике работу со стандартом JSON.

Необходимо лишь импортировать модуль в начале файла:

import json

Маленький словарь

Теперь нам надо ознакомиться с термином сериализация, который означает кодирование информации в JSON. Также это слово означает превращение информации в серию байтов (следовательно, серийных) для того, чтобы хранить эти данные или передавать по сети. 

Соответственно, десериализацией называется противоположный процесс, в ходе которого данные декодируются. 

Фактически, все это можно свести к чтению и написанию.

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

Что будет после того, как компьютер обработает большие массивы данных? Ему необходимо принять дамп данных. Следовательно, модуль json может использоваться для этого. А именно, метод dump(), который позволяет записывать информацию в файлы. 

Также можно записывать данные в строку Python с помощью метода dumps().

Объекты Python могут переводиться в стандарт JSON в соответствии с интуитивно понятной концепцией. Главное – понимать, что делает тот или иной объект, и запомнить этот список будет несложно. В целом, можно ориентироваться на эту таблицу до тех пор, пока знания не отложатся в памяти. 

Python JSON
dict object
list, tuple array
str string
int, long, float number
True true
False false
None null

Пример сериализации JSON Python

А теперь давайте вообразим, что мы взаимодействуем с объектом Python в памяти. Сам объект выглядит так. 

data = {
    "president": {
        "name": "Zaphod Beeblebrox",
        "species": "Betelgeusian"
    }
}

Сохранение данной информации на диск является принципиально важным, поэтому главная задача – записать на файл.  С помощью контекстного менеджера Python, можно создать файл, имеющий имя data_file.json и запустить его в режиме редактирования.

Учтите то, что данные формата JSON имеют одноименное расширение .json.

with open("data_file.json", "w") as write_file:
    json.dump(data, write_file)

Также необходимо учитывать факт того, что dump() передается два позиционных аргумента: 

  1. Сериализуемый объект.
  2. Файловый объект.

Или, если вы желаете продолжать пользоваться такими сериализованными данными в приложении Python, то с ними можно взаимодействовать, как с объектами строкового типа:

json_string = json.dumps(data)

Учтите то, что объект файлового типа пустой, поскольку вы не производите запись. Помимо этого, dumps() фактически выполняет роль аналога dump()

Отлично, теперь у нас вышел небольшой блок JSON, и теперь его можно использовать.

Ряд нужных аргументов

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

Поэтому необходимо обеспечить такой синтаксис, чтобы даже человек с относительно неразвитыми навыками разработки мог понимать, что делает тот или иной блок программы.

Правда, одного лишь читабельного синтаксиса явно не хватит, если все находится вместе. Кроме этого, ваш метод разработки приложений имеет определенные различия с тем, который практикуется для создания примеров выше. Поэтому рекомендуется форматировать вышеприведенный код так, как будет удобно вам. Впрочем, это не обязательно.

Первая опция, которую подавляющее число людей желают изменить, это пробел. Возможно использование аргумента indent, чтобы определить величину отступа вложенных структур. Посмотрите на различие с помощью приведенных ранее данных и запустите такие команды: 

json.dumps(data)
json.dumps(data, indent=4)

Еще один способ, с помощью которого возможно осуществление форматирования – это использование аргумента separators. Если не менять настроек, это двойной кортеж строк разделителя, но, как правило, в роли аналога для компактного JSON является («,», «:»). Гляньте на пример повторно, чтобы посмотреть, начинают работать разделители. 

Имеются и иные аргументы, такие как sort_keys. Также можете ознакомиться с документацией, чтобы получить подробное понимание.

Десериализация JSON

Модуль json содержит load() и loads() для трансформации кодированных сведений формата JSON в объекты Python. Можем привести таблицу с моделью, по которой будет совершаться конверсия данных для десериализации. По ней вы можете получить понимание того, как все выглядит.

JSON Python
object dict
array list
string str
number (int) int
number (real) float
true True
false False
null None

Видим, что все работает точно так же, как в предыдущей таблице. Просто наоборот. 

Технически, этот вариант конверсии не идеально подходит для таблицы сериализации. Фактически это говорит о том, что если вы прямо в сей момент выполните кодирование объекта, а потом осуществите его декодирование, вы рискуете получить несколько другой объект. То есть, он будет отличаться от того, который был на входе. 

Это напоминает определенную телепортацию. Предположим, молекулы человека разбираются в точке А и собираются в точке Б. Будет ли этот человек таким самым? Формально да, но будут определенные отличия. Ведь условия в точке А и точке Б отличаются.

В реальности это напоминает двойной перевод через онлайн-переводчик. Например, если перевести что-то на английский язык, а потом выполнить противоположную операцию. Отличия все же будут. В этом можно убедиться, если вы используете онлайн-переводчик и попробуете сами перевести какую-то фразу туда и назад.

Впрочем, наиболее легким вариантом будет кодирование кортежа, а потом получение назад списка после выполнения обратной операции (то есть, декодирования). По такому образу: 

blackjack_hand = (8, "Q")
encoded_hand = json.dumps(blackjack_hand)
decoded_hand = json.loads(encoded_hand)
print(blackjack_hand == decoded_hand) # False
print(type(blackjack_hand)) # <class 'tuple'>
print(type(decoded_hand)) # <class 'list'>
print(blackjack_hand == tuple(decoded_hand)) # True

Десериализация: пример

Теперь давайте вообразим, что имеются определенные сведения на жестком диске, и ими вы желаете оперировать в ОЗУ. Вам по прежнему важно пользоваться контекстным менеджером, но сейчас необходимо открыть имеющийся data_file.json в режиме, не предусматривающем внесение какие-либо изменения (для чтения): 

with open("data_file.json", "r") as read_file:
    data = json.load(read_file)

Здесь все, в принципе, понятно. Но необходимо помнить, что вследствие выполнения данного метода могут быть возвращены все имеющиеся типы объектов, которые были приведены в таблице ранее. Это требуется лишь тогда, когда загружается информация, которой ранее не было обнаружено. В подавляющем числе случаев, в качестве корневого объекта будет выступать dict или list.

Если вы записали сведения JSON из другого приложения или была каким-то иным методом получена строка JSON форматированных данных в Python, можно использовать функцию loads() для их десериализации. Загрузка легко осуществляется из строки: 

json_string = """
{
    "researcher": {
        "name": "Ford Prefect",
        "species": "Betelgeusian",
        "relatives": [
            {
                "name": "Zaphod Beeblebrox",
                "species": "Betelgeusian"
            }
        ]
    }
}
"""
data = json.loads(json_string)

Пример работы с данной библиотекой Python

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

Сперва необходимо создать файл, который называется scratch.py. Или можно дать любое другое название. Далее следует осуществить запрос API в JSONPlaceholder

Кто не знает, он позволяет работать с запросами на сервер.

Далее добавьте такие импорты вверху кода: 

import json
import requests

На данном этапе необходимо поработать с TODOs и создать запрос в API JSONPlaceholder для конечной точки GET /todos. Если вам запросы знакомы недостаточно, можно воспользоваться невероятно удобным методом json(), выполняющим всю работу вместо вас. Вы можете попытаться выполнить десериализацию атрибута текста объекта response. Это будет работать приблизительно так (естественно, эти строки вы можете изменять под свои задачи, мы приводим лишь пример для наглядности): 

response = requests.get("https://jsonplaceholder.typicode.com/todos")
todos = json.loads(response.text)

А теперь попробуйте непосредственно убедиться в том, что этот фрагмент кода работает. Вставьте эти строчки в свою программу и попробуйте их запустить средствами интерпретатора Python. 

Также выполните проверку типа todos. Если интересно, обратите внимание на первые десять элементом, которые находятся в этом списке: 

response = requests.get("https://jsonplaceholder.typicode.com/todos")
todos = json.loads(response.text)
print(todos == response.json()) # True
print(type(todos)) # <class 'list'>
print(todos[:10]) # ..

Все это необходимо проверять в интерактивном режиме. Что это такое? Это специальный флаг -i, когда запускается скрипт.

Увидеть структуру данных, которые получены от тестового API, можно по этому адресу: https://jsonplaceholder.typicode.com/todos. Здесь есть все необходимые сведения для обучения. Мы же приведем здесь фрагмент, демонстрирующий, как это работает.  

{
    "userId": 1,
    "id": 1,
    "title": "delectus aut autem",
    "completed": false
}

Здесь есть определенное количество юзеров, каждый из которых имеет уникальный userid, а каждая задача имеет свойство Boolean. Как же понять, кто выполнил подавляющее число задач? Для этого выполняются такие действия. Приведем большой код, который нужно тщательно проанализировать: 

response = requests.get("https://jsonplaceholder.typicode.com/todos")
todos = json.loads(response.text)
# Соотношение userId с числом выполненных пользователем задач.
todos_by_user = {}
# Увеличение выполненных задач каждым пользователем.
for todo in todos:
    if todo["completed"]:
        try:
            # Увеличение количества существующих пользователей.
            todos_by_user[todo["userId"]] += 1
        except KeyError:
            # Новый пользователь, ставим кол-во 1.
            todos_by_user[todo["userId"]] = 1
# Создание отсортированного списка пар (userId, num_complete).
top_users = sorted(todos_by_user.items(), 
                   key=lambda x: x[1], reverse=True)
#Получение максимального количества выполненных задач.
max_complete = top_users[0][1]
# Создание списка всех пользователей, которые выполнили
# максимальное количество задач.
users = []
for user, num_complete in top_users:
    if num_complete < max_complete:
        break
    users.append(str(user))
max_users = " and ".join(users)

Так можно манипулировать данными JSON так, как обычным объектом Python. Ведь их можно конвертировать друг в друга.

Заключение

Таким образом, мы разобрались в основных аспектах работы с JSON. Мы поняли, что это отличная библиотека для обмена информацией, и у нее много возможностей. Также ее преимущества: легкая портируемость в разные языки программирования, а также высокая читабельность как для компьютера, так и для человека.

Это очень полезно, когда над созданием приложения работает целая команда. С такими преимуществами нет ничего удивительного в том, что JSON обрел столь широкое распространение среди разработчиков Python и других языков программирования.

Но, естественно, мы рассмотрели не все аспекты работы с JSON. Чтобы максимально понимать то, как работать с этим стандартом обмена информацией, нужно рассмотреть еще некоторые моменты. Но они будут в ⇒ следующей публикации.

ОфисГуру
Adblock
detector