Python LanguageМодуль JSON

замечания

Для полной документации, включая функциональность, зависящую от версии, ознакомьтесь с официальной документацией .

Типы

Значения по умолчанию

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

Типы де-сериализации:

JSON питон
объект ДИКТ
массив список
строка ул
число (int) ИНТ
номер (реальный) поплавок
true, false Правда, ложь
ноль Никто

Модуль json также понимает NaN , Infinity и -Infinity как их соответствующие значения float, которые находятся вне спецификации JSON.

Типы сериализации:

питон JSON
ДИКТ объект
список, кортеж массив
ул строка
int, float, (int / float) -перечисленный Enums число
Правда правда
Ложь ложный
Никто ноль

Чтобы запретить кодирование NaN , Infinity и -Infinity вы должны закодировать с allow_nan=False . Это приведет к повышению значения ValueError если вы попытаетесь закодировать эти значения.

Пользовательская (де-) сериализация

Существуют различные крючки, которые позволяют обрабатывать данные, которые должны быть представлены по-разному. Использование functools.partial позволяет вам частично применить соответствующие параметры к этим функциям для удобства.

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

Вы можете предоставить функцию, которая работает с объектами до их сериализации следующим образом:

# my_json module

import json
from functools import partial

def serialise_object(obj):
    # Do something to produce json-serialisable data
    return dict_obj

dump = partial(json.dump, default=serialise_object)
dumps = partial(json.dumps, default=serialise_object)

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

Существуют различные крючки, которые обрабатываются функциями json, такими как object_hook и parse_float. Для исчерпывающего списка вашей версии python см. Здесь .

# my_json module

import json
from functools import partial

def deserialise_object(dict_obj):
    # Do something custom
    return obj

def deserialise_float(str_obj):
    # Do something custom
    return obj

load = partial(json.load, object_hook=deserialise_object, parse_float=deserialise_float)
loads = partial(json.loads, object_hook=deserialise_object, parse_float=deserialise_float)

Дальнейшая настройка (дезактивация):

Модуль json также позволяет расширять / заменять json.JSONEncoder и json.JSONDecoder для обработки разных типов. Крюки, описанные выше, могут быть добавлены как значения по умолчанию, создав эквивалентный именованный метод. Чтобы использовать их, просто передайте класс как параметр cls в соответствующую функцию. Использование functools.partial позволяет частично применить параметр cls к этим функциям для удобства, например

# my_json module

import json
from functools import partial

class MyEncoder(json.JSONEncoder):
    # Do something custom

class MyDecoder(json.JSONDecoder):
    # Do something custom

dump = partial(json.dump, cls=MyEncoder)
dumps = partial(json.dumps, cls=MyEncoder)
load = partial(json.load, cls=MyDecoder)
loads = partial(json.loads, cls=MyDecoder)

Создание JSON из Python dict

import json
d = {
    'foo': 'bar',
    'alice': 1,
    'wonderland': [1, 2, 3]
}
json.dumps(d)

Вышеприведенный фрагмент возвращает следующее:

'{"wonderland": [1, 2, 3], "foo": "bar", "alice": 1}'

Создание Python dict из JSON

import json
s = '{"wonderland": [1, 2, 3], "foo": "bar", "alice": 1}'
json.loads(s)

Вышеприведенный фрагмент возвращает следующее:

{u'alice': 1, u'foo': u'bar', u'wonderland': [1, 2, 3]}

Хранение данных в файле

Следующий фрагмент кодирует данные, хранящиеся в d в JSON, и сохраняет их в файле (замените filename на фактическое имя файла).

import json

d = {
    'foo': 'bar',
    'alice': 1,
    'wonderland': [1, 2, 3]
}

with open(filename, 'w') as f:
    json.dump(d, f)

Извлечение данных из файла

Следующий фрагмент открывает JSON-кодированный файл (заменяет filename фактическим именем файла) и возвращает объект, который хранится в файле.

import json

with open(filename, 'r') as f:
    d = json.load(f)

`load` vs` load`, `dump` vs` dumps`

Модуль json содержит функции как для чтения, так и для записи в строки Unicode, а также для чтения и записи в файлы и из них. Они дифференцируются по завершению s в имени функции. В этих примерах мы используем объект StringIO, но те же функции применимы к любому файлоподобному объекту.

Здесь мы используем строковые функции:

import json

data = {u"foo": u"bar", u"baz": []}
json_string = json.dumps(data)
# u'{"foo": "bar", "baz": []}'
json.loads(json_string)
# {u"foo": u"bar", u"baz": []}

И здесь мы используем файловые функции:

import json

from io import StringIO

json_file = StringIO()
data = {u"foo": u"bar", u"baz": []}
json.dump(data, json_file)
json_file.seek(0)  # Seek back to the start of the file before reading
json_file_content = json_file.read()
# u'{"foo": "bar", "baz": []}'
json_file.seek(0)  # Seek back to the start of the file before reading
json.load(json_file)
# {u"foo": u"bar", u"baz": []}

Как вы можете видеть, основное отличие заключается в том, что при распаковке json-данных вы должны передать дескриптор файла функции, а не захватывать возвращаемое значение. Также стоит отметить, что перед чтением или письмом вы должны искать начало файла, чтобы избежать повреждения данных. При открытии файла курсор помещается в позицию 0 , так что ниже также будет работать:

import json

json_file_path = './data.json'
data = {u"foo": u"bar", u"baz": []}

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

with open(json_file_path) as json_file:
    json_file_content = json_file.read()
    # u'{"foo": "bar", "baz": []}'

with open(json_file_path) as json_file:
    json.load(json_file)
    # {u"foo": u"bar", u"baz": []}

Имея оба способа работы с json-данными, вы можете идиоматически и эффективно работать с форматами, которые основываются на json, например pyspark -per-line pyspark :

# loading from a file
data = [json.loads(line) for line in open(file_path).splitlines()]

# dumping to a file
with open(file_path, 'w') as json_file:
    for item in data:
        json.dump(item, json_file)
        json_file.write('\n')

Вызов `json.tool` из командной строки для вывода корректного вывода JSON

Учитывая некоторый JSON-файл «foo.json», например:

{"foo": {"bar": {"baz": 1}}}

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

$ python -m json.tool foo.json
{
    "foo": {
        "bar": {
            "baz": 1
        }
    }
}

Модуль также будет принимать входные данные от STDOUT, поэтому (в Bash) мы одинаково можем:

$ cat foo.json | python -m json.tool

Форматирование вывода JSON

Допустим, у нас есть следующие данные:

>>> data = {"cats": [{"name": "Tubbs", "color": "white"}, {"name": "Pepper", "color": "black"}]}

Просто демпинг это, поскольку JSON не делает ничего особенного здесь:

>>> print(json.dumps(data))
{"cats": [{"name": "Tubbs", "color": "white"}, {"name": "Pepper", "color": "black"}]}

Настройка отступа для получения более красивого результата

Если мы хотим печатать, мы можем установить размер indent :

>>> print(json.dumps(data, indent=2))
{
  "cats": [
    {
      "name": "Tubbs",
      "color": "white"
    },
    {
      "name": "Pepper",
      "color": "black"
    }
  ]
}

Сортировка клавиш в алфавитном порядке для получения согласованного вывода

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

>>> print(json.dumps(data, sort_keys=True))
{"cats": [{"color": "white", "name": "Tubbs"}, {"color": "black", "name": "Pepper"}]}

Как избавиться от пробелов, чтобы получить компактный выход

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

>>>print(json.dumps(data, separators=(',', ':')))
{"cats":[{"name":"Tubbs","color":"white"},{"name":"Pepper","color":"black"}]}

JSON-кодирование пользовательских объектов

Если мы просто попробуем следующее:

import json
from datetime import datetime
data = {'datetime': datetime(2016, 9, 26, 4, 44, 0)}
print(json.dumps(data))

мы получаем сообщение об ошибке: TypeError: datetime.datetime(2016, 9, 26, 4, 44) is not JSON serializable .

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

class DatetimeJSONEncoder(json.JSONEncoder):
    def default(self, obj):
        try:
            return obj.isoformat()
        except AttributeError:
            # obj has no isoformat method; let the builtin JSON encoder handle it
            return super(DatetimeJSONEncoder, self).default(obj)

а затем используйте этот класс энкодера вместо json.dumps :

encoder = DatetimeJSONEncoder()
print(encoder.encode(data))
# prints {"datetime": "2016-09-26T04:44:00"}