Модуль 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 выполняется в соответствии с соглашениями, приведенными в таблице ниже:
JSON | Python |
---|---|
object | dict |
array | list |
string | str |
number (int) | int |
number (real) | float |
true | True |
false | False |
null | None |
Давайте продемонстрируем на нескольких примерах сопоставления, показанные в таблице преобразования 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(), происходят две вещи:
- Объект JSON отображается в несколько строк и поэтому более удобен для чтения.
- Каждому атрибуту объекта 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 — один из форматов обмена данными между системами, и он не зависит от языка программирования, на котором построены системы.