Как использовать JSON в Python

Модуль Python json позволяет использовать данные в формате JSON в ваших приложениях. Хотите преобразовать объект Python в JSON или наоборот? Это подходящий модуль для этого.

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

В этом уроке мы научимся использовать модуль Python json для выполнения сериализации и десериализации данных с использованием формата JSON.

Начнем с рассмотрения двух функций, предоставляемых модулем json: dumps() и loads().

Что такое JSON-дампы в Python?

Функция json.dumps() преобразует объект Python в строку в формате JSON.

Процесс преобразования объекта Python в строку JSON называется сериализацией. Этот процесс также называется кодированием.

Например, давайте определим словарь Python:

>>> user = {'name': 'John', 'email': 'test@email.com'}
>>> type(user)
<class 'dict'>

И посмотрим, какой вывод мы получим, когда передадим его функции json.dumps().

>>> import json
>>> user_json = json.dumps(user)
>>> print(user_json)
{"name": "John", "email": "test@email.com"}
>>> type(user_json)
<class 'str'> 

Функция dumps преобразовала (сериализовала) словарь в строку JSON.

Буква «s» в названии функции dumps указывает на то, что эта функция работает со строками (в отличие от функции dump(), которая работает с файлами).

Что такое JSON-загрузки в Python?

Процесс преобразования строки JSON в объект Python называется десериализацией. Этот процесс также называется декодированием.

Функция json.loads() выполняет десериализацию строки JSON в объект Python.

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

>>> user = json.loads(user_json)
>>> print(user)
{'name': 'John', 'email': 'test@email.com'}
>>> type(user)
<class 'dict'> 

Точно так же, как мы видели в функции json.dumps(), имя функции json.loads() заканчивается буквой «s».

Это связано с тем, что он применяется к строкам JSON, а не к файлам JSON (для этого следует использовать функцию json.load()).

Как прочитать файл JSON в Python?

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

Поведение такое же, как у функции loads(), с той лишь разницей, что loads() применяется к строкам, а load() — к файлам.

Вот как можно прочитать данные JSON из файла. Я создал файл posts.json со следующим содержимым:

[
  { 
    "userId": 1,
    "postId": 1,
    "title": "How to Convert a JSON Object into a Python Object"
  },
  { 
    "userId": 1,
    "postId": 2,
    "title": "How to Convert a Python Object into a JSON Object"
  }
] 

Допустим, я хочу прочитать название первого поста.

Во-первых, давайте преобразуем JSON в файле в объект Python с помощью load(). Чтобы открыть файл, мы будем использовать менеджер контекста with open, который автоматически закрывает файл, когда он больше не нужен.

>>> import json
>>> with open('posts.json') as json_file:
...     data = json.load(json_file)
... 
>>> print(data)
[{'userId': 1, 'postId': 1, 'title': 'How to Convert a JSON Object into a Python Object'}, {'userId': 1, 'postId': 2, 'title': 'How to Convert a Python Object into a JSON Object'}]
>>> print(type(data))
<class 'list'> 

Мы преобразовали (или декодировали, или десериализовали) наши данные в список.

Убедимся, что элементы списка являются словарями:

>>> print(type(data[0]))
<class 'dict'> 

Это хорошо, это означает, что для получения заголовка первого поста мы можем просто обратиться к ключу «title» словаря data[0].

>>> print(data[0]['title'])
How to Convert a JSON Object into a Python Object 

Как написать JSON-файл на Python?

Мы увидели, как считывать данные JSON из файла и преобразовывать их в объект Python.

Как можно сделать наоборот?

Модуль Python json предоставляет функцию dump(), которая записывает объект Python в файл в формате JSON.

Начнем с объекта Python, созданного в предыдущем разделе:

>>> data = [{'userId': 1, 'postId': 1, 'title': 'How to Convert a JSON Object into a Python Object'}, {'userId': 1, 'postId': 2, 'title': 'How to Convert a Python Object into a JSON Object'}] 

Вместо того чтобы просто записать эти данные в файл JSON, мы сначала изменим данные.

В результате мы хотим получить объект JSON, в котором оба элемента содержат новый пустой атрибут под названием «body».

Добавьте ключ «body» в оба словаря внутри нашего списка Python, а затем запишите объект в файл с помощью функции dump().

>>> data[0]['body'] = ''
>>> data[1]['body'] = ''
>>> print(data)
[{'userId': 1, 'postId': 1, 'title': 'How to Convert a JSON Object into a Python Object', 'body': ''}, {'userId': 1, 'postId': 2, 'title': 'How to Convert a Python Object into a JSON Object', 'body': ''}]
>>> with open('posts.json') as json_file:
...     json.dump(data, json_file)
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/opt/anaconda3/lib/python3.8/json/__init__.py", line 180, in dump
    fp.write(chunk)
io.UnsupportedOperation: not writable 

Используя with open и функцию dump(), мы записываем в файл posts.json. Обратите внимание, что функция dump() принимает объект Python в качестве первого аргумента и объект файла в качестве второго аргумента.

Однако мы получаем исключение, связанное с тем, что объект файла недоступен для записи.

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

>>> with open('posts.json', 'w') as json_file:
...     json.dump(data, json_file)
... 
>>>  

На этот раз все хорошо!

Давайте прочитаем содержимое обновленного файла JSON, чтобы убедиться, что оба элемента имеют атрибут «body»:

>>> with open('posts.json') as json_file:
...     print(json_file.read())
... 
[{"userId": 1, "postId": 1, "title": "How to Convert a JSON Object into a Python Object", "body": ""}, {"userId": 1, "postId": 2, "title": "How to Convert a Python Object into a JSON Object", "body": ""}] 

Да, файл JSON обновился, как мы и ожидали!

Таблица преобразования JSON в Python

Преобразование объекта JSON в объект Python выполняется в соответствии с соглашениями, приведенными в таблице ниже:

JSONPython
objectdict
arraylist
stringstr
number (int)int
number (real)float
trueTrue
falseFalse
nullNone

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

Мы уже видели раньше, что часто при десериализации строки JSON результатом является словарь.

Например, давайте десериализуем следующий массив JSON:

>>> weekdays_json = '["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]' 

Чтобы преобразовать этот массив в объект Python, мы можем использовать функцию loads().

>>> import json
>>> weekdays = json.loads(weekdays_json)
>>> print(weekdays)
['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
>>> print(type(weekdays))
<class 'list'> 

Вы можете видеть, что после декодирования массива JSON мы получили список Python.

>>> print(weekdays[2])
Wednesday 

Давайте посмотрим, что произойдет, если объект JSON содержит массив в качестве одного из своих значений.

>>> json_value = '{"weekdays": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]}'
>>> value = json.loads(json_value)
>>> print(value)
 {'weekdays': ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']}
>>> print(type(value))
<class 'dict'> 

Как показано в таблице преобразования, объект JSON становится словарем.

В то же время значение внутри нашего объекта JSON, сопоставленное с ключом «weekdays», было массивом JSON, а теперь это список Python.

>>> print(type(value['weekdays']))
<class 'list'> 

Преобразование логических, числовых и нулевых значений из JSON в Python

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

>>> json_value = '{"value1": true, "value2": false, "value3": 1, "value4": 3.4, "value5": null}'
>>> value = json.loads(json_value)
>>> print(value)
{'value1': True, 'value2': False, 'value3': 1, 'value4': 3.4, 'value5': None} 

Вы можете видеть, что после декодирования нашего JSON-объекта происходит следующее:

  • правда становится правдой.
  • ложь становится ложью.
  • целые и вещественные числа становятся числами Python int и float.
  • null становится None.
>>> print(type(value['value1']))
<class 'bool'>
>>> print(type(value['value2']))
<class 'bool'>
>>> print(type(value['value3']))
<class 'int'>
>>> print(type(value['value4']))
<class 'float'>
>>> print(type(value['value5']))
<class 'NoneType'> 

Как теперь вернуться от объекта Python к строке JSON?

Мы можем использовать функцию json.dumps()

>>> print(value)
{'value1': True, 'value2': False, 'value3': 1, 'value4': 3.4, 'value5': None}
>>> json_value = json.dumps(value)
>>> print(json_value)
{"value1": true, "value2": false, "value3": 1, "value4": 3.4, "value5": null} 

И вуаля, мы получили исходный объект JSON.

Как красиво распечатать данные JSON

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

>>> print(json_value)
{"value1": true, "value2": false, "value3": 1, "value4": 3.4, "value5": null}

Это может сработать, если объект JSON не содержит слишком много атрибутов и если его значения не слишком длинные.

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

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

Для решения этой проблемы существует необязательный аргумент indent, который мы можем передать функции dumps() при кодировании объекта Python в JSON.

Посмотрите, как изменится закодированный JSON, если мы передадим три разных значения для отступа: 0, 1 и 2.

>>> print(json.dumps(value, indent=0))
{
"value1": true,
"value2": false,
"value3": 1,
"value4": 3.4,
"value5": null
} 
>>> print(json.dumps(value, indent=1))
{
 "value1": true,
 "value2": false,
 "value3": 1,
 "value4": 3.4,
 "value5": null
} 
>>> print(json.dumps(value, indent=2))
{
  "value1": true,
  "value2": false,
  "value3": 1,
  "value4": 3.4,
  "value5": null
} 

Когда мы передаем аргумент отступа в функцию json.dumps(), происходят две вещи:

  1. Объект JSON отображается в несколько строк и поэтому более удобен для чтения.
  2. Каждому атрибуту объекта JSON предшествует несколько пробелов, размер которых зависит от значения отступа.

Разделители для объектов JSON в Python

Функции json.dumps и json.dump также принимают необязательный аргумент, называемый разделителями, который представляет собой кортеж в следующем формате:

(item_separator, key_separator)

Как вы можете себе представить, изменение разделителей элементов и ключей полностью меняет внешний вид объекта JSON.

Значение разделителя по умолчанию, используемое в Python для кодирования объектов в JSON, — (‘, ‘, ‘: ‘).

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

>>> print(json.dumps(value, indent=2))
{
  "value1": true,
  "value2": false,
  "value3": 1,
  "value4": 3.4,
  "value5": null
} 

Теперь обратите внимание на разницу, если мы изменим значение аргумента разделителей.

Мы можем удалить пробелы, чтобы получить более компактное представление JSON:

>>> print(json.dumps(value, indent=2, separators=(',',':')))
{
  "value1":true,
  "value2":false,
  "value3":1,
  "value4":3.4,
  "value5":null
} 

Сортировка ключей объекта JSON

В некоторых случаях может быть удобно иметь возможность сортировать ключи в объекте JSON.

Представьте, что у вас есть объект JSON, имеющий 100 ключей…

…если их упорядочить, объект станет более читабельным.

Вот как можно отсортировать ключи объекта JSON.

Например, начнем со следующего объекта Python, преобразованного в объект JSON:

>>> user = {'name': 'John', 'surname': 'Red', 'age':35}
>>> print(json.dumps(user))
{"name": "John", "surname": "Red", "age": 35} 

Вы видите, что ключи объекта JSON не отсортированы.

Для сортировки ключей объекта JSON при его кодировании из объекта Python можно использовать аргумент sort_keys — логическое значение, значением по умолчанию которого является False.

>>> print(json.dumps(user, sort_keys=True))
{"age": 35, "name": "John", "surname": "Red"} 

В результате на этот раз атрибуты JSON сортируются в алфавитном порядке.

Использование цикла For для печати элементов в массиве JSON

Предположим, у нас есть следующий JSON-файл с именем users.json, содержащий сведения обо всех пользователях, подписавшихся на ваш сервис:

{
  "users": [
    {
      "id": 1,
      "first_name": "John",
      "last_name": "Red",
      "email": "johnred@example.com"
    },
    {
      "id": 2,
      "first_name": "Mike",
      "last_name": "Yellow",
      "email": "mikeyellow@example.com"
    },
    {
      "id": 3,
      "first_name": "Jane",
      "last_name": "Green",
      "email": "janegreen@example.com"
    }
  ]
} 

Как можно использовать цикл for в Python для обхода каждого пользователя в массиве JSON?

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

>>> import json
>>> with open('users.json') as json_file:
...     data = json.load(json_file)
... 
>>> print(data)
{'users': [{'id': 1, 'first_name': 'John', 'last_name': 'Red', 'email': 'johnred@example.com'}, {'id': 2, 'first_name': 'Mike', 'last_name': 'Yellow', 'email': 'mikeyellow@example.com'}, {'id': 3, 'first_name': 'Jane', 'last_name': 'Green', 'email': 'janegreen@example.com'}]}
>>> print(type(data))
<class 'dict'> 

Используя load(), мы создали объект Python с именем data, который затем можно использовать для чтения сведений о каждом пользователе.

Объект Python — это словарь, чтобы пройти по каждому пользователю, нам сначала нужно получить доступ к ключу ‘users’. Затем пройдемся по нему с помощью цикла for:

>>> for user in data['users']:
...     print(user)
... 
{'id': 1, 'first_name': 'John', 'last_name': 'Red', 'email': 'johnred@example.com'}
{'id': 2, 'first_name': 'Mike', 'last_name': 'Yellow', 'email': 'mikeyellow@example.com'}
{'id': 3, 'first_name': 'Jane', 'last_name': 'Green', 'email': 'janegreen@example.com'} 

Имеет ли это смысл?

Как получить JSON из API с помощью Python

Но как бы вы использовали на практике то, что мы узнали к настоящему моменту?

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

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

В этом примере мы будем использовать следующий API, который возвращает породы собак:

https://dog.ceo/api/breeds/list/all

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

Если вы откроете этот URL в своем браузере, вы увидите ответ API…

…но как мы можем получить ответ с помощью Python?

Мы можем использовать модуль urllib.request для выполнения запроса GET к конечной точке API:

>>> import urllib.request
>>> response = urllib.request.urlopen('https://dog.ceo/api/breeds/list/all').read().decode()

Давайте выведем первые 200 символов ответа, используя оператор среза:

>>> print(response[:200])
{"message":{"affenpinscher":[],"african":[],"airedale":[],"akita":[],"appenzeller":[],"australian":["shepherd"],"basenji":[],"beagle":[],"bluetick":[],"borzoi":[],"bouvier":[],"boxer":[],"brabancon":[ 

Теперь мы можем использовать наши знания в области манипулирования данными JSON для преобразования ответа, поступающего от API, в объект Python с помощью json.loads().

>>> import json
>>> data = json.loads(response)
>>> print(type(data))
<class 'dict'>
>>> print(data['message']['terrier'])
['american', 'australian', 'bedlington', 'border', 'dandie', 'fox', 'irish', 'kerryblue', 'lakeland', 'norfolk', 'norwich', 'patterdale', 'russell', 'scottish', 'sealyham', 'silky', 'tibetan', 'toy', 'westhighland', 'wheaten', 'yorkshire'] 

В результате мы получили обратно словарь и теперь можем получить доступ к любым необходимым нам данным.

Заключение

Теперь у вас есть знания, как использовать модуль json для выполнения следующих задач:

  • сериализация (кодирование): преобразование объекта Python в объект JSON.
  • десериализация (декодирование): преобразование объекта JSON в объект Python.

Мы узнали, что для работы со строками JSON можно использовать json.dumps() и json.loads(). Для работы с файлами JSON можно использовать json.dump() и json.load().

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

JSON — один из форматов обмена данными между системами, и он не зависит от языка программирования, на котором построены системы.

Автор

Фото аватара

Владимир Михайлов

Программист на Python с большим количеством опыта и разнообразных проектов.