class FileItem:
def __init__(self, fname):
self.fname = fname
Что мне делать, чтобы получить вывод:
>>> import json
>>> my_file = FileItem('/foo/bar')
>>> json.dumps(my_file)
TypeError: Object of type 'FileItem' is not JSON serializable
Без ошибки
К сожалению, все ответы, кажется, отвечают на вопрос, как сериализовать класс? вместо вопроса о действии Как мне сделать класс сериализуемым? Эти ответы предполагают, что вы сами выполняете сериализацию, а не передаете объект какому-либо другому модулю, который его сериализует. Kyle Delaney 18.10.2019
Если вы используете Python3.5 +, вы можете использовать jsons. Он преобразует ваш объект (и все его атрибуты рекурсивно) в dict. import jsons см. Ответ ниже - он отлично работает tswaehn 02.04.2020
@KyleDelaney Я действительно надеялся на интерфейс / магический метод, который я мог бы реализовать, чтобы он стал доступным для поиска. Я предполагаю, что мне придется реализовать функцию .to_dict() или что-то, что может быть вызвано для объекта, прежде чем он будет передан модулю, который пытается его сериализовать. Felix B. 01.09.2020
см. stackoverflow.com/a/63718624/1497139 для начала работы с примесью JSONAble Wolfgang Fahl 03.09.2020
@FelixB. Вы можете использовать встроенную функцию vars в сочетании с json.dumps (см. Мой ответ stackoverflow.com/a/64469761/1587520 ) user1587520 23.11.2020
У вас есть представление об ожидаемом результате? Например, подойдет ли это?
>>> 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>
>>>
Ответ 2 · рейтинг 729 · Onur Yıldırım
Вот простое решение для простой функции:
.toJSON() Метод
Вместо сериализуемого класса JSON реализуйте метод сериализатора:
Для более сложных классов вы можете использовать инструмент jsonpickle:
jsonpickle - это библиотека Python для сериализации и десериализации сложных объектов Python в JSON и обратно.
Стандартные библиотеки Python для кодирования Python в JSON, такие как json из stdlib, simplejson и demjson, могут обрабатывать только примитивы Python, которые имеют прямой эквивалент JSON (например, dicts, списки, строки, int и т. Д.). jsonpickle строится поверх этих библиотек и позволяет сериализовать более сложные структуры данных в JSON. jsonpickle обладает широкими возможностями настройки и расширения, что позволяет пользователю выбирать серверную часть JSON и добавлять дополнительные серверные части.
Большинство ответов связано с изменением вызова на 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
Это работает, если ваш класс представляет собой просто базовое представление данных, для более сложных вещей вы всегда можете явно указать ключи.
Ответ 5 · рейтинг 59 · Jason S
Мне нравится ответ Онура, но я бы расширил его, включив дополнительный метод toJSON() для сериализации объектов:
Это обезьяна исправляет json-модуль при его импорте, поэтому JSONEncoder.default () автоматически проверяет наличие специального метода to_json () и использует его для кодирования объекта, если он найден.
Как и сказал Онур, но на этот раз вам не нужно обновлять все json.dumps() в вашем проекте.
Ответ 7 · рейтинг 42 · Paulo Freitas
Другой вариант - обернуть дамп JSON в отдельный класс:
Или, что еще лучше, создать подкласс класса FileItem из класса JsonSerializable:
import json
class JsonSerializable(object):
def toJson(self):
return json.dumps(self.__dict__)
def __repr__(self):
return self.toJson()
class FileItem(JsonSerializable):
def __init__(self, fname):
self.fname = fname
Тестирование:
>>> f = FileItem('/foo/bar')
>>> f.toJson()
'{"fname": "/foo/bar"}'
>>> f
'{"fname": "/foo/bar"}'
>>> str(f) # string coercion
'{"fname": "/foo/bar"}'
Ответ 8 · рейтинг 30 · user1587520
Как упоминалось во многих других ответах, вы можете передать функцию json.dumps для преобразования объектов, которые не являются одним из типов, поддерживаемых по умолчанию, в поддерживаемый тип. Удивительно, но ни один из них не упоминает простейший случай - использование встроенной функции vars для преобразования объектов в словарь, содержащий все их атрибуты:
json.dumps(obj, default=vars)
Обратите внимание, что это охватывает только базовые случаи, если вам нужна более конкретная сериализация для определенных типов (например, исключение определенных атрибутов или для объектов, у которых нет атрибута __dict__), вам необходимо использовать настраиваемую функцию или JSONEncoder, как описано в других ответах .
Ответ 9 · рейтинг 29 · tobigue
На днях я столкнулся с этой проблемой и реализовал более общую версию кодировщика для объектов Python, который может обрабатывать вложенные объекты и унаследованные поля:
import json
import inspect
class ObjectEncoder(json.JSONEncoder):
def default(self, obj):
if hasattr(obj, "to_json"):
return self.default(obj.to_json())
elif hasattr(obj, "__dict__"):
d = dict(
(key, value)
for key, value in inspect.getmembers(obj)
if not key.startswith("__")
and not inspect.isabstract(value)
and not inspect.isbuiltin(value)
and not inspect.isfunction(value)
and not inspect.isgenerator(value)
and not inspect.isgeneratorfunction(value)
and not inspect.ismethod(value)
and not inspect.ismethoddescriptor(value)
and not inspect.isroutine(value)
)
return self.default(d)
return obj
Пример:
class C(object):
c = "NO"
def to_json(self):
return {"c": "YES"}
class B(object):
b = "B"
i = "I"
def __init__(self, y):
self.y = y
def f(self):
print "f"
class A(B):
a = "A"
def __init__(self):
self.b = [{"ab": B("y")}]
self.c = C()
print json.dumps(A(), cls=ObjectEncoder, indent=2, sort_keys=True)
Если вы используете Python3.5 +, вы можете использовать jsons. (PyPi: https://pypi.org/project/jsons/) Он преобразует ваш объект (и все его атрибуты рекурсивно) в dict.
import jsons
a_dict = jsons.dump(your_object)
Или, если вам нужна строка:
a_str = jsons.dumps(your_object)
Или, если ваш класс реализовал jsons.JsonSerializable:
a_dict = your_object.json
Ответ 11 · рейтинг 12 · tryer3000
import simplejson
class User(object):
def __init__(self, name, mail):
self.name = name
self.mail = mail
def _asdict(self):
return self.__dict__
print(simplejson.dumps(User('alice', '[email protected]')))
при использовании стандартного json необходимо определить функцию default
json ограничен с точки зрения объектов, которые он может напечатать, а jsonpickle (вам может понадобиться pip install jsonpickle) ограничен с точки зрения того, что он не может отступать от текста. Если вы хотите проверить содержимое объекта, класс которого вы не можете изменить, я все равно не смог бы найти более простой способ, чем: