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"}