JSON – это формат передачи данных, определенный стандартом RFC 7159 и ECMA-404. Основан на синтаксисе JavaScript, но не относится к нему. Если вы использовали стандартные модули marshal и pickle, то вам уже эти API должны быть знакомыми.
Объекты Python могут быть преобразованы в формат json. Вот пример кода, который демонстрирует это.
>>> import json >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) '["foo", {"bar": ["baz", null, 1.0, 2]}]' >>> print(json.dumps("\"foo\bar")) "\"foo\bar" >>> print(json.dumps('\u1234')) "\u1234" >>> print(json.dumps('\\')) "\\" >>> print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)) {"a": 0, "b": 0, "c": 0} >>> from io import StringIO >>> io = StringIO() >>> json.dump(['streaming API'], io) >>> io.getvalue() '["streaming API"]'
А вот вариант компактного преобразования.
>>> import json >>> print(json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4)) { "4": 5, "6": 7 }
После передачи данных в формате JSON необходимо осуществить их декодирование. То есть, превратить в объект Python. Это делается так, как приводится в этом примере кода.
>>> import json >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') ['foo', {'bar': ['baz', None, 1.0, 2]}] >>> json.loads('"\\"foo\\bar"') '"foo\x08ar' >>> from io import StringIO >>> io = StringIO('["streaming API"]') >>> json.load(io) ['streaming API']
Если говорить о специализированном декодировании объектов в JSON, то оно осуществляется таким образом.
>>> import json >>> def as_complex(dct): ... if '__complex__' in dct: ... return complex(dct['real'], dct['imag']) ... return dct ... >>> json.loads('{"__complex__": true, "real": 1, "imag": 2}', ... object_hook=as_complex) (1+2j) >>> import decimal >>> json.loads('1.1', parse_float=decimal.Decimal) Decimal('1.1')
А этот фрагмент кода демонстрирует использование расширения JSONEncoder.
>>> import json >>> class ComplexEncoder(json.JSONEncoder): ... def default(self, obj): ... if isinstance(obj, complex): ... return [obj.real, obj.imag] ... # Let the base class default method raise the TypeError ... return json.JSONEncoder.default(self, obj) ... >>> json.dumps(2 + 1j, cls=ComplexEncoder) '[2.0, 1.0]' >>> ComplexEncoder().encode(2 + 1j) '[2.0, 1.0]' >>> list(ComplexEncoder().iterencode(2 + 1j)) ['[2.0', ', 1.0', ']']
Читатель может подумать: «А чего это меня грузят фрагментами кода с самого начала? Я ничего не понимаю». Ну ладно. Давайте сначала разберемся в том, что такое Json и какие его основные методы.
Что такое JSON?
Это формат, предназначенный для передачи данных. Сам этот формат текстовый. В качестве значений могут использоваться:
- Другой JSON-объект.
- Массив данных.
- Число.
- Булевые значения.
- Строки.
Давайте для большего понимания рассмотрим массивы и объекты.
JSON-объект
Для начала приведем фрагмент кода, а потом разберемся, что он означает.
{ "query": "Виктор Иван", "count": 7 }
Видим, что объекты заключаются в фигурные скобки. Они свидетельствуют о начале и конце объекта.
Во всем остальном, JSON-объекты чем-то напоминают словари в Python, поскольку являют собой множество пар «ключ:значение». Серверу передается ключ, который служит идентификатором параметра.
Например, серверу передается значение «Виктор Иван». И он такой думает «И что бы это значило». Начинает искать и понимает: «А, это query».
То есть, JSON используется для передачи серверу запроса от клиента. Внутри одного объекта могут находиться и другие объекты. Причем количество уровней вложенности большое.
Еще одно понятие, характеризующее объект JSON – свойство. Как отличить его от ключа? Очень просто. Свойство – это комбинация ключа и значение. На практике же свойства называются по ключах. Но если мы говорим про ключ, то понимать, что речь идет только о первой составляющей свойства.
JSON-массив
Массив можно отличить по квадратным скобкам.
[ «MALE», «FEMALE» ]
Массив используется для хранения набора значений. В отличие от объекта, здесь нет ключей. Следовательно, можно обращаться к массиву исключительно по номеру элемента.
В отличие от объекта, массив является упорядоченным множеством значений. Этот объект соответствует списку Python.
Объекты JSON и Python
Каждый элемент JSON соответствует определенному объекту в Python. Чтобы перевести его в формат Python, существует класс json.JSONDecoder(*, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True, object_pairs_hook=None).
Выполняет декодирование в соответствии с типом объекта. Вот таблица, описывающая объекты и их соответствия в Python и JSON.
JSON | Python |
object | dict |
array | list |
string | str |
number (int) | int |
number (real) | float |
true | True |
false | False |
null | None |
Этот декодер также может распознавать NaN, Infinity, -Infinity в качестве соответствующих значений float, которые не находятся внутри спецификации JSON.
Соответственно, кроме декодирования также можно выполнять кодирование. Для этого используется класс json.JSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None).
Использует те же самые типы объектов, что и декодировщик. То есть, с помощью Python можно осуществлять как кодирование, так и декодирование объектов.
Но это мы немного забежали наперед. Давайте рассмотрим базовые методы, которые позволяют технически наладить работу с JSON.
Метод json dump
Этот метод используется для того, чтобы сериализовать объект в JSON-подобный формат. Для этого осуществляется запись в fp (поддерживающий .write()).
Синтаксис метода следующий (в скобках приводятся аргументы и значения по умолчанию, если не задано иное).
json.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
Стандартное значение skipkeys – false. Тем не менее, если его установить на True, ключи словарей, которые не принадлежат к целочисленному, строковому, булевому, нулевому типам, а также – числу с плавающей точкой, пропускаются. Если же использовать стандартное значение, то тогда метод говорит об ошибке TypeError.
Простыми словами, можно использовать исключительно стандартные типы, которые могут конвертироваться в JSON.
Модуль json всегда осуществляет генерацию строковых объектов. Таким образом, fp.write() должен поддерживать ввод строковых данных.
Рассмотрим еще некоторые аргументы, которые передаются этому методу.
-
- ensure_ascii. Если стоит значение по умолчанию, все символы, не относящиеся к ASCII, экранируются в выводе с использованием последовательностей \uXXXX. Если значение установлено на False, то тогда запись будет осуществляться в первоначальном виде.
- check_circular. Если установлено значение не по умолчанию (то есть, False), то тогда проверка циклических ссылок для типов контейнера не осуществляется. Ссылки же будут вызывать OverflowError или другую ошибку.
- allow_nan. Стандартное значение – True, но если поставить значение False, то при попытке сериализовать значение float, которое выходит за допустимые пределы, то будет возникать ошибка. Если оставить значение по умолчанию, то будут использоваться JavaScript аналоги.
- indent. Определяет отступы. Если значение этого элемента – целое неотрицательное число или строка, то объекты и массивы JSON будут идти на вывод с этим количеством отступов. Если же уровень равняется 0, он отрицательный или «», то тогда используются новые строки без отступов. Если задать значение по умолчанию, то будет использоваться самое компактное представление. Если же в качестве аргумента используется строка, то она и используется в качестве отступа. В версии 3,2 разрешено использовать для отступа вместе с целочисленными значениями данные строчного формата.
- Separators. Значения по умолчанию – (‘, ‘, ‘: ‘). Чтобы представление сделать компактным, необходимо удалить из аргументов пробелы.
- sort_keys. Если стоит значение по умолчанию, то ключи выводимого словаря не сортируются. Если использовать значение True (а по умолчанию было, как вы могли догадаться, False), то ключи сортируются.
JSON dumps
С помощью этого метода осуществляется сериализация obj в строчный формат JSON. Для этого используется таблица выше.
Синтаксис метода следующий.
json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
JSON Load
Этот метод осуществляет десериализацию из fp в Python-объект. Для этого использует приведенную выше таблицу конвертации. Аргументы этого метода следующие.
- object_hook. Эта функция необязательна для использования. Она применяется к результату декодирования объекта. Здесь используется значение, возвращаемое функцией, а не словарь.
- object_pair_shook. Применяется к результату декодирования объекта с определенной последовательностью ключа и значения. Вместо исходного словаря будет использоваться тот результат, который выдала эта функция.
- parse_float. Если он определяется, то вызывается для каждого JSON-значения типа float.
- parse_int. Аналог предыдущей функции, но используется с целочисленными значениями.
- parse_constant. Может использоваться для вызова исключений, если обнаруживаются числа, которые являются в JSON недопустимыми.
Это не все методы, которые используются в JSON, но самые основные. На самом деле, работа с этим форматом требует нескольких статей, чтобы рассмотреть все.