Как сделать класс Python сериализуемым?
Простой класс:
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
Без ошибки
python
json
serialization
Сергей
источник
источник
import jsons
см ответ ниже - это отлично работаетОтветы:
У вас есть представление об ожидаемом выходе? Например, это будет делать?
В этом случае вы можете просто позвонить
json.dumps(f.__dict__)
.Если вы хотите получить более персонализированный вывод, вам придется создать подкласс
JSONEncoder
и реализовать собственную настраиваемую сериализацию.Для тривиального примера см. Ниже.
Затем вы передаете этот класс в
json.dumps()
метод какcls
kwarg:Если вы также хотите декодировать, вам нужно будет предоставить пользовательский класс
object_hook
дляJSONDecoder
класса. Например,источник
__dict__
не будет работать во всех случаях. Если атрибуты не были установлены после создания объекта,__dict__
возможно, заполнение не полностью. В приведенном выше примере вы в порядке, но если у вас есть атрибуты класса, которые вы также хотите закодировать, они не будут перечислены в списке,__dict__
если они не были изменены в__init__
вызове класса или каким-либо другим способом после создания экземпляра объекта.from_json()
функция, используемая в качестве объектного хука, должна иметьelse: return json_object
оператор, поэтому она может работать и с общими объектами.__dict__
также не работает, если вы используете__slots__
новый класс стилей.JSONEncoder
как описано выше, для создания пользовательского протокола, например, для проверки существования__json_serializable__
метода и вызова его для получения сериализуемого представления объекта в формате JSON. Это было бы в соответствии с другими шаблонами Python, как__getitem__
,__str__
,__eq__
, и__len__
.__dict__
также не будет работать рекурсивно, например, если атрибут вашего объекта является другим объектом.Вот простое решение для простой функции:
.toJSON()
методВместо сериализуемого класса JSON реализуйте метод сериализатора:
Так что вы просто вызываете его для сериализации:
будет выводить:
источник
o.__dict___
. Попробуйте свой собственный пример:class MyObject(): def __init__(self): self.prop = 1 j = json.dumps({ "foo": "bar", "baz": MyObject() }, default=lambda o: o.__dict__)
a.__dict__
/b.__dict__
.datetime.datetime
экземплярами. Выдает следующую ошибку:'datetime.datetime' object has no attribute '__dict__'
Для более сложных классов вы можете рассмотреть инструмент jsonpickle :
(ссылка на jsonpickle на PyPi)
источник
jsonpickle
объект. Кроме того, это не было в состоянии расшифровать диктовку, содержащую кадры данных панд.obj = jsonpickle.decode(file.read())
иfile.write(jsonpickle.encode(obj))
.Большинство ответов включают изменение вызова json.dumps () , что не всегда возможно или желательно (например, это может происходить внутри компонента фреймворка).
Если вы хотите иметь возможность вызывать json.dumps (obj) как есть, тогда простое решение наследуется от dict :
Это работает, если ваш класс является просто базовым представлением данных, для более сложных вещей вы всегда можете установить ключи явно.
источник
dumps
не является хорошим решением. Кстати, в большинстве случаев вы, вероятно, хотите иметьdict
наследование вместе с делегированием, что означает, что у вас будет некоторыйdict
атрибут типа внутри вашего класса, затем вы передадите этот атрибут в качестве параметра в качестве инициализации, что-то вродеsuper().__init__(self.elements)
.Мне нравится ответ Онура, но я бы его расширил, добавив дополнительный
toJSON()
метод для сериализации объектов:источник
json.dumps
и введением пользовательской обработки. Спасибо!try-catch
этого, вероятно, сделайте что-то вродеif 'toJSON' in obj.__attrs__():
... чтобы избежать тихого сбоя (в случае сбоя в toJSON () по какой-то другой причине, чем его не было) ... сбоя, который потенциально может привести к повреждению данных.Другой вариант - обернуть дамп JSON в свой собственный класс:
Или, что еще лучше, создание подкласса класса FileItem из
JsonSerializable
класса:Тестирование:
источник
__json__encode__
/__json_decode__
(раскрытие: я сделал последний).Просто добавьте
to_json
метод в ваш класс следующим образом:И добавьте этот код (из этого ответа ) , где-нибудь наверху всего:
Это будет обезьяна-патч для модуля json при его импорте, поэтому JSONEncoder.default () автоматически проверяет наличие специального метода «to_json ()» и использует его для кодирования объекта, если он найден.
Точно так же, как сказал Онур, но на этот раз вам не нужно обновлять каждое
json.dumps()
в вашем проекте.источник
TheObject.to_json = my_serializer
.Я столкнулся с этой проблемой на днях и реализовал более общую версию Encoder для объектов Python, которая может обрабатывать вложенные объекты и унаследованные поля :
Пример:
Результат:
источник
return obj
последней строки я сделал этоreturn super(ObjectEncoder, self).default(obj)
. Ссылка ЗДЕСЬЕсли вы используете Python3.5 +, вы можете использовать
jsons
. Он преобразует ваш объект (и все его атрибуты рекурсивно) в диктовку.Или, если вы хотите строку:
Или если ваш класс реализован
jsons.JsonSerializable
:источник
jsons
библиотеку с классами данных . Пока все хорошо для меня!если использовать стандарт
json
, вам нужно определитьdefault
функциюисточник
json.dumps(User('alice', 'alice@mail.com'), default=lambda x: x.__dict__)
json
ограничен с точки зрения объектов, которые он может печатать, иjsonpickle
(вам может понадобитьсяpip install jsonpickle
) ограничен с точки зрения невозможности отступа текста. Если вы хотите проверить содержимое объекта, класс которого вы не можете изменить, я все равно не смог бы найти более прямой путь, чем:Примечание: они все еще не могут печатать методы объекта.
источник
Этот класс может сделать свое дело, он конвертирует объект в стандартный JSON.
Применение:
работая в
python2.7
аpython3
.источник
источник
default(obj)
является функцией, которая должна возвращать сериализуемую версию obj или вызывать TypeError. По умолчаниюdefault
просто возникает ошибка TypeError.Харако дал довольно аккуратный ответ. Мне нужно было исправить некоторые мелочи, но это работает:
Код
Обратите внимание, что нам нужно два шага для загрузки. На данный момент
__python__
свойство не используется.Насколько это распространено?
Используя метод AlJohri , я проверяю популярность подходов:
Сериализация (Python -> JSON):
to_json
: 266 595 на 2018-06-27toJSON
: 96 307 на 2018-06-27__json__
: 8,504 на 2018-06-27for_json
: 6,937 на 2018-06-27Десериализация (JSON -> Python):
from_json
: 226 101 на 2018-06-27источник
Это хорошо сработало для меня:
а потом
а также
источник
Если вы не против установить пакет для него, вы можете использовать json-tricks :
После этого вам нужно просто импортировать
dump(s)
изjson_tricks
вместо JSON, и это будет обычно работать:который даст
И это в основном все!
Это будет отлично работать в целом. Есть некоторые исключения, например, если происходят какие-то особые вещи
__new__
, или происходит больше магии метакласса.Очевидно, что загрузка также работает (иначе какой смысл):
Предполагается, что он
module_name.test_class.MyTestCls
может быть импортирован и не изменился несовместимыми способами. Вы получите обратно экземпляр , а не какой-то словарь или что-то еще, и это должна быть копия, идентичная копии, которую вы сбросили.Если вы хотите настроить сериализацию чего-либо (де), вы можете добавить специальные методы в ваш класс, например так:
который сериализует только часть параметров атрибутов, в качестве примера.
И в качестве бесплатного бонуса вы получаете (де) сериализацию массивов, даты и времени, упорядоченные карты, а также возможность добавлять комментарии в json.
Отказ от ответственности: я создал json_tricks , потому что у меня была та же проблема, что и у вас.
источник
Jsonweb кажется лучшим решением для меня. Смотрите http://www.jsonweb.info/en/latest/
источник
Вот мои 3 цента ...
Это демонстрирует явную сериализацию json для древовидного объекта python.
Примечание. Если вам действительно нужен какой-то подобный код, вы можете использовать витой класс FilePath .
источник
Я столкнулся с этой проблемой, когда попытался сохранить модель Peewee в PostgreSQL
JSONField
.После некоторой борьбы вот общее решение.
Ключом к моему решению является прохождение исходного кода Python и понимание того, что документация кода (описанная здесь ) уже объясняет, как расширить существующий
json.dumps
для поддержки других типов данных.Предположим, что у вас есть модель, которая содержит некоторые поля, которые нельзя сериализовать в JSON, и модель, которая содержит поле JSON, изначально выглядит так:
Просто определите обычай
JSONEncoder
как это:А затем просто используйте его в вашем
JSONField
виде ниже:Ключ
default(self, obj)
метод выше. Для каждой... is not JSON serializable
жалобы, которую вы получаете от Python, просто добавьте код для обработки типа unserializable-to-JSON (например,Enum
ordatetime
)Например, вот как я поддерживаю класс, наследующий от
Enum
:Наконец, с помощью кода, реализованного, как описано выше, вы можете просто преобразовать любые модели Peewee в объект с поддержкой JSON, как показано ниже:
Хотя приведенный выше код был (несколько) специфичен для Peewee, но я думаю:
json.dumps
работает, это решение также работает с Python (без ORM) в целом тожеЛюбые вопросы, пожалуйста, оставляйте в разделе комментариев. Спасибо!
источник
Эта функция использует рекурсию для итерации по каждой части словаря, а затем вызывает методы repr () классов, которые не являются встроенными.
источник
Это небольшая библиотека, которая сериализует объект со всеми его потомками в JSON, а также анализирует его обратно:
https://github.com/Toubs/PyJSONSerialization/
источник
Я придумал собственное решение. Используйте этот метод, передайте любой документ ( dict , list , ObjectId и т. Д.) Для сериализации.
источник
Я решил использовать декораторы для решения проблемы сериализации объекта datetime. Вот мой код:
Импортируя вышеупомянутый модуль, мои другие модули используют json обычным способом (без указания ключевого слова по умолчанию) для сериализации данных, которые содержат объекты даты и времени. Код сериализатора datetime автоматически вызывается для json.dumps и json.dump.
источник
Мне больше всего понравился метод Lost Koder. Я столкнулся с проблемами при попытке сериализовать более сложные объекты, члены / методы которых не сериализуемы. Вот моя реализация, которая работает на большем количестве объектов:
источник
Если вы можете установить пакет, я бы порекомендовал попробовать укроп , который отлично работал для моего проекта. Приятной особенностью этого пакета является то, что он имеет тот же интерфейс, что и
pickle
, если вы уже использовали егоpickle
в своем проекте, вы можете просто заменить егоdill
и посмотреть, запускается ли скрипт, без изменения какого-либо кода. Так что это очень дешевое решение!(Полное противодействие раскрытию информации: я никоим образом не связан и никогда не участвовал в проекте укропа.)
Установите пакет:
Затем отредактируйте код для импорта
dill
вместоpickle
:Запустите ваш скрипт и посмотрите, работает ли он. (Если это так, вы можете очистить свой код, чтобы больше не скрывать
pickle
имя модуля!)Некоторые особенности типов данных, которые
dill
могут и не могут быть сериализованы на странице проекта :источник
Я не вижу здесь упоминания о последовательном версионировании или backcompat, поэтому я опубликую свое решение, которое я использовал немного. Мне, наверное, есть чему поучиться, в частности, Java и Javascript, вероятно, более зрелые, чем я, но здесь
https://gist.github.com/andy-d/b7878d0044a4242c0498ed6d67fd50fe
источник
Чтобы добавить еще один вариант: вы можете использовать
attrs
пакет иasdict
метод.и конвертировать обратно
класс выглядит так
источник
В дополнение к ответу Onur , вы, возможно, захотите иметь дело с типом datetime, как показано ниже.
(для обработки: объект datetime.datetime не имеет атрибута ' dict ' исключение.)
Применение:
источник
Сначала нам нужно сделать наш объект JSON-совместимым, чтобы мы могли вывести его с помощью стандартного модуля JSON. Я сделал это так:
источник
Опираясь на Quinten Cabo «S ответ :
Различия
list
иtuple
(она работает для массивов NumPy и т. Д.)__dict__
).float
иNone
поэтому они не преобразуются в строки.В качестве упражнения для читателя
__slots__
оставлено обрабатывать классы, которые являются итеративными и имеют члены, классы, являющиеся словарями, а также членами и т. Д.источник