Вопрос-Ответ

How to make a class JSON serializable

Как сделать класс JSON сериализуемым

Как сделать класс Python сериализуемым?

class FileItem:
def __init__(self, fname):
self.fname = fname

Попытка сериализации в JSON:

>>> import json
>>> x = FileItem('/foo/bar')
>>> json.dumps(x)
TypeError: Object of type 'FileItem' is not JSON serializable
Переведено автоматически
Ответ 1

Вот простое решение для простой функции:

.toJSON() Метод

Вместо сериализуемого в формате JSON класса реализуйте метод сериализатора:

import json

class Object:
def toJSON(self):
return json.dumps(self, default=lambda o: o.__dict__,
sort_keys=True, indent=4)

Итак, вы просто вызываете его для сериализации:

me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"

print(me.toJSON())

выведет:

{
"age": 35,
"dog": {
"name": "Apollo"
},
"name": "Onur"
}
Ответ 2

У вас есть представление об ожидаемом результате? Например, подойдет ли это?

>>> f  = FileItem("/foo/bar")
>>> magic(f)
'{"fname": "/foo/bar"}'

В этом случае вы можете просто вызвать json.dumps(f.__dict__).

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

Тривиальный пример смотрите ниже.

>>> from json import JSONEncoder
>>> class MyEncoder(JSONEncoder):
def default(self, o):
return o.__dict__

>>> MyEncoder().encode(f)
'{"fname": "/foo/bar"}'

Затем вы передаете этот класс в json.dumps() метод как cls kwarg:

json.dumps(cls=MyEncoder)

Если вы также хотите декодировать, вам придется предоставить пользовательский object_hook для JSONDecoder класса. Например:

>>> def from_json(json_object):
if 'fname' in json_object:
return FileItem(json_object['fname'])
>>> f = JSONDecoder(object_hook = from_json).decode('{"fname": "/foo/bar"}')
>>> f
<__main__.FileItem object at 0x9337fac>
>>>
Ответ 3

Для более сложных классов вы могли бы рассмотреть инструмент jsonpickle:


jsonpickle - это библиотека Python для сериализации и десериализации сложных объектов Python в JSON и из него.


Стандартные библиотеки Python для кодирования Python в JSON, такие как json stdlib, simplejson и demjson, могут обрабатывать только примитивы Python, которые имеют прямой эквивалент JSON (например, dicts, списки, строки, целые числа и т.д.). jsonpickle строится поверх этих библиотек и позволяет сериализовывать более сложные структуры данных в JSON. jsonpickle легко настраивается и расширяется – позволяет пользователю выбирать серверную часть JSON и добавлять дополнительные серверные части.


Преобразование объекта в строку JSON:

import jsonpickle
json_string = jsonpickle.encode(obj)

Воссоздать объект Python из строки JSON:

recreated_obj = jsonpickle.decode(json_string)

(ссылка на jsonpickle в PyPI)

Ответ 4

Большинство ответов связаны с изменением вызова на json.dumps(), что не всегда возможно или желательно (например, это может произойти внутри компонента фреймворка).

Если вы хотите иметь возможность вызывать json.dumps(obj) как есть, то простым решением является наследование от dict:

class FileItem(dict):
def __init__(self, fname):
dict.__init__(self, fname=fname)

f = FileItem('tasks.txt')
json.dumps(f) #No need to change anything here

Это работает, если ваш класс представляет собой просто базовое представление данных, для более сложных задач вы всегда можете явно задать ключи в вызове dict.__init__().

Это работает, потому что json.dumps() проверяет, является ли объект одним из нескольких известных типов с помощью довольно непитонического isinstance(value, dict) - так что можно было бы подделать это с помощью __class__ и некоторых других методов, если вы действительно не хотите наследовать от dict.

2023-04-26 16:46 python json