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

Обновлено: 07.07.2024

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

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

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

Для тривиального примера см. Ниже.

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

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

Я не вижу здесь упоминания о последовательном версионировании или backcompat, поэтому я опубликую свое решение, которое я использовал немного. Мне, наверное, есть чему поучиться, в частности, Java и Javascript, вероятно, более зрелые, чем я, но здесь

Просто добавьте метод to_json в ваш класс следующим образом:

И добавьте этот код (из этого ответа) , где-нибудь наверху всего:

Как сказал Онур, но на этот раз вам не нужно обновлять каждый json.dumps() в вашем проекте.

Я решил использовать декораторы для решения проблемы сериализации объекта datetime. Вот мой код:

Импортируя вышеупомянутый модуль, мои другие модули используют json обычным способом (без указания ключевого слова по умолчанию) для сериализации данных, которые содержат объекты даты и времени. Код сериализатора datetime автоматически вызывается для json.dumps и json.dump.

Я столкнулся с этой проблемой на днях и реализовал более общую версию Encoder для объектов Python, которая может обрабатывать вложенные объекты и унаследованные поля :

Вот мои 3 цента .
Это демонстрирует явную сериализацию JSON для древовидного объекта Python.
Примечание. Если вам действительно нужен какой-то подобный код, вы можете использовать витой FilePath class.

Это небольшая библиотека, которая сериализует объект со всеми его потомками в JSON, а также анализирует его обратно:

Или, если вы хотите строку:

Или если ваш класс реализовал jsons.JsonSerializable :

Чтобы добавить другой вариант: Вы можете использовать пакет attrs и метод asdict .

И конвертировать обратно

Класс выглядит так

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

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

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

Мне нравится ответ Онура, но я бы его расширил, добавив дополнительный метод toJSON() для объектов, чтобы сериализовать себя:

Я придумал собственное решение. Используйте этот метод, передайте любой документ ( dict , список , ObjectId и т. Д.) Для сериализации.

Мне больше всего понравился метод Lost Koder. Я столкнулся с проблемами при попытке сериализации более сложных объектов, члены / методы которых не сериализуемы. Вот моя реализация, которая работает на большем количестве объектов:

Сначала нам нужно сделать наш объект JSON-совместимым, чтобы мы могли вывести его с помощью стандартного модуля JSON. Я сделал это так:

Если вы не против установить пакет для него, вы можете использовать json-tricks :

После этого вам просто нужно импортировать dump(s) из json_tricks вместо json, и это обычно будет работать:

И это в основном все!

Это будет отлично работать в целом. Есть некоторые исключения, например если в __new__ происходит что-то особенное, или происходит больше магии метакласса.

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

Это предполагает, что module_name.test_class.MyTestCls может быть импортирован и не изменился несовместимыми способами. Вы получите обратно экземпляр , а не какой-либо словарь или что-то в этом роде, и он должен быть идентичным копии, которую вы сбросили.

Если вы хотите настроить сериализацию чего-либо (де), вы можете добавить специальные методы в ваш класс, например:

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

И в качестве бесплатного бонуса вы получаете (де) сериализацию массивов, даты и времени, упорядоченные карты, а также возможность добавлять комментарии в json.

Отказ от ответственности: я создал json_tricks, потому что у меня была та же проблема, что и у вас.

В дополнение к ответу Onur, вы, возможно, захотите иметь дело с типом datetime, как показано ниже.
(чтобы handle: у объекта datetime.datetime нет атрибута dict . Исключение.)

Я столкнулся с этой проблемой, когда попытался сохранить модель Peewee в PostgreSQL JSONField .

После некоторой борьбы вот общее решение.

Ключом к моему решению является изучение исходного кода Python и понимание того, что документация кода (описана здесь) уже объясняет, как расширить существующий json.dumps для поддержки других типов данных.

Предположим, у вас есть модель, которая содержит некоторые поля, которые нельзя сериализовать в JSON, и модель, которая содержит поле JSON, изначально выглядит так:

Просто определите пользовательский JSONEncoder следующим образом:

А затем просто используйте его в своем JSONField , как показано ниже:

Ключ - default(self, obj) метод выше. Для каждой жалобы . is not JSON serializable , которую вы получаете от Python, просто добавьте код для обработки типа, не поддающегося обработке в JSON (например, Enum или datetime )

Например, вот как я поддерживаю класс, унаследованный от Enum :

Наконец, с помощью кода, реализованного, как описано выше, вы можете просто преобразовать любые модели Peewee в объект с поддержкой JSON, как показано ниже:

Хотя приведенный выше код был (несколько) специфичен для Peewee, но я думаю:

  1. Это применимо к другим ORM (Django и т. Д.) В целом
  2. Кроме того, если вы поняли, как работает json.dumps , это решение также работает с Python (без ORM) в целом.

Любые вопросы, пожалуйста, оставляйте в разделе комментариев. Спасибо!

Если вы можете установить пакет, я бы порекомендовал попробовать укроп, который отлично работал для мой проект. Приятной особенностью этого пакета является то, что он имеет тот же интерфейс, что и pickle , поэтому, если вы уже использовали pickle в своем проекте, вы можете просто заменить его в dill и посмотреть, если скрипт работает, без изменения какого-либо кода. Так что это очень дешевое решение!

(Полное противодействие раскрытию информации: я никоим образом не связан и никогда не участвовал в проекте укропа.)

Затем отредактируйте свой код для импорта dill вместо pickle :

Запустите ваш скрипт и посмотрите, работает ли он. (Если это так, вы можете очистить свой код, чтобы больше не скрывать имя модуля pickle !)

Некоторые сведения о типах данных, которые dill могут и не могут сериализовать, можно найти на странице проекта:

json ограничен с точки зрения объектов, которые он может печатать, а jsonpickle (вам может потребоваться pip install jsonpickle ) ограничен с точки зрения невозможности отступа текста. Если вы хотите проверить содержимое объекта, класс которого вы не можете изменить, я все равно не смог бы найти более прямой путь, чем:

Примечание: они все еще не могут распечатать методы объекта.

Этот класс может сделать свое дело, он конвертирует объект в стандартный JSON.

Работает в python2.7 и python3 .

Если использовать стандарт json , вам нужно определить функцию default

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

.toJSON() Метод

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

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

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

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

У меня это хорошо сработало:

Есть много подходов к этой проблеме. ObjDict (pip install objdict) - это другое. Особое внимание уделяется предоставлению javascript-подобных объектов, которые также могут действовать как словари для лучшей обработки данных, загружаемых из JSON, но есть и другие функции, которые также могут быть полезны. Это обеспечивает другое альтернативное решение исходной проблемы.

Обратите внимание, что нам нужно два шага для загрузки. На данный момент, свойство __python__ не используется

Насколько это распространено?

Используя метод AlJohri, я проверяю популярность подходов:

Сериализация (Python -> JSON):

Десериализация (JSON -> Python):

Другой вариант - обернуть дамп JSON в свой собственный класс:

Или, что еще лучше, создание подкласса класса FileItem из класса JsonSerializable :

Сериализация - процесс преобразования некоторого объекта (класса) в последовательность байтов с целью сохранения в памяти (базе данных, файле), отправки объекта удаленному приложению посредством веб-службы, передача объекта из одного домена в другой, передача объекта через брандмауэр в виде XML-строки и хранение информации о безопасности или конкретном пользователе, используемой несколькими приложениями. Сериализация - процесс двунаправленный и имеет целью не только сохранить и передать в удобном виде данных, но и возможность воссоздать его при необходимости в виде исходного объекта. Обратный процесс называется десериализацией.

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

Кроме того, для того, чтобы сериализация стала возможной необходимо также объявление пространств имен:

Дополнительно в объекте часть информации может требовать или не требовать сохранения и дальнейшего восстановления, в этом случае применяется метки-атрибуты [SerializableAttribute] и [NonSerializedAttribute].

Cериализуемая информация содержит не только данные, но и сведения о типе объекта (версию, язык и региональные параметры, а также имя сборки).

Основную информацию по выполнению сериализации проводит специальный объект - Formatter.

Как мы уже отмечали, различают двоичную и XML-сериализацию. При XML-сериализации информация сериализуется в XML-поток. XML-сериализация может также использоваться для сериализации объектов в потоки XML, которые соответствуют спецификации SOAP (Simple Object Access Protocol — простой протокол доступа к объектам). SOAP - это протокол, основанный на XML и созданный специально для передачи вызовов процедур с использованием XML.

Подробно мы будем говорить о XML-сериализации, когда руки автора доберутся до Web-сервисов. А пока познакомимся с двоичной сериализацией в файлы. И последнее замечание перед приведением примера использования сериализации, мы отмечали, что сериализованная информация хранит версию приложения и ряд других его атрибутов. Один из способов обойти это - настраиваемая сериализация, когда можно указать какие объекты будут сериализованы, и как будет производиться сериализация. Существует способ обхода этого варианта, связанные с сериализацией конструктора и некоторыми другими тонкостями, которые выходит за рамки статьи.

Впервые я использовал сериализацию при создании Русско-японского переводчика с целью хоть по минимуму защить труд автора словаря - вытащить из двоичного исходного файла Excel исходный документ словаря практически невозможно. Вот на этом примере я и покажу механизм двоичной сериализации.

Параграф 2. Пример создания класса для двоичной сериализации

Итак, создадим пустое пока решение (например, с именем myProject) приложения и добавим к нему класс, который будет выполнять функции словаря. В окне "Solutation Explorer" (Меню Viev | Solutation Explorer) выполним правый клик мышкой на файле проекта и добавим новую опцию (Рис.1.).


Рис.1 Создание приложения и добавление класса для сериализации


Рис.2 Создание приложения и добавдение класса для сериализации

В код класса, который мы хотим сделать сериализуемым добавим помеченный как сериализуемый объект - [Serializable]:

В класс dictionary добавим методы, делающие класс словарем, например Hashtable, предоставляющую коллекцию пар ключ/значение, которые упорядочены по хэш-коду ключа и которая собственно будет хранить словарь. При добавлении элемента в коллекцию Hashtable он помещается в определенный сегмент в зависимости от хэш-кода ключа. В дальнейшем поиск ключа осуществляется только в определенном сегменте с использованием хэш-кода ключа. Таким образом, в значительной степени уменьшается количество операций сравнения ключей, которое требуется для нахождения элемента. Итак, первым добавим:

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

Параграф 3. Работа по сериализации и десериализации класса

Первым в основном приложении добавляем необходимые пространства имен, а именно:

И соответственно объявляем потомка созданного класса, и делаем из него рабочий класс - workDict=new workDict(); :

Далее можно пользоваться методами добавления и удаления данных в словарь, описанных выше.

Осталось сохранить словарь в сериализованном виде и загрузить вновь словарь в память.

Запись можно выполнить так (sCurDir - текущая директория старта приложения - там мы будем размещать и словарь):

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

Вот и все тонкости работы по двоичной сериализации и десиреализации, приведенные на кокретном примере работы со словарем.

Сериализация – это сохранение типа и состояния объекта в бинарном виде для последующего сохранения/передачи и десериализации. Для сериализации используется интерфейс Serializable ( Externalizable ), и цель записи/источник чтения ObjectInputStream / ObjectOutputStream ( ObjectInput / ObjectOutput ).

Класс сериализуем, если:
🔘 Реализует маркерный интерфейс Serializable ;
🔘 Все поля сериализуемые или помечены модификатором transient (иначе рантайм выбросит NotSerializableException ).

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

Для описания полей сериализационной формы в javadoc-документации используется тэг @serial . Для документации генерирующего нестандартную сериализационную форму метода используется @serialData . Эти тэги имеют смысл и для приватных членов, так как эффективно такие члены – часть публичного API.

Нестатические внутренние классы не должны быть сериализуемыми. Статические поля как поля класса а не инстанса несериализуемы.

Сериализации посвящен целый раздел Effective Java. Доклад для ознакомления с темой.

Этот класс должен быть реализован, если вам нужно сохранить объект на диск или перенести его через сеть.SerializableИнтерфейс илиExternalizableОдин из интерфейсов.

1、Serializable

1.1 Обычная сериализация

Интерфейс Serializable - это интерфейс тегов без реализации. Как только этот интерфейс будет реализован, объект этого класса сериализован.

Шаг 1: создать выходной выход ObjectoutStream;

Шаг 2: Вызов на выходе из ссылки на вывод объекта ObjectoutStream может быть сериализован.

Шаг 1: Создание входного потока ObjectInputStream;

Шаг 2: Вызовите readObject () объекта ObjectInputStream, чтобы получить сериализованный объект.

Мы будем сериализовать выше к человеку личности.

Waht . Вывод говорит нам, что десериализация не вызывает конструктора. Объектом определения является объект, генерируемый JVM, и не генерируется методом конструкции.

1.2 участник является последовательностью ссылки

Если член сериализованного класса не является базовым типом, он не является типом строки, который также должен быть сериализован; в противном случае этот класс не может быть сериализован.

См. Пример, мы добавили класс учителя. Удалите человека, чтобы реализовать сериализуемый интерфейсный код.

Мы видим, что программа непосредственно сообщается, поскольку объект класса человека неоспоримо, что приводит к тому, что объект учителя будет проинтересован.

1.3 Последовательность Много механизма того же объекта

Будет ли эта последовательность объектов несколько раз в том же объекте?ответотрицательныйиз.

Последовательность в файле Weacher.txt файл последовательно последовательно последовательно.

Примечание. Порядок, в котором обратная последовательность соответствует порядку сериализации.。

Как видно из результатов вывода,Java сериализует тот же объект и не сериализует этот объект несколько раз несколько раз.

Все объекты, сохраненные на диске, имеют код сериализации

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

Если этот объект уже сериализован, номер может быть выведен напрямую.

Вышеуказанный процесс сериализации проиллюстрирован.

1.4 Алгоритм агоритма для сериализации Java

Поскольку алгоритм последовательности Java не повторяет последовательность одного и того же объекта, только количество сериализованных объектов будет записано только.Если сериализованный объект переменной (содержимое в объекте может быть изменен), содержимое объекта изменяется, а затем снова сериализуется, и объект снова не будет преобразован в последовательность байтов, но только сохраняет номер сериализации.

1.5 Дополнительные пользовательские серии

Иногда у нас такая потребность, некоторые атрибуты не требуют сериализации.Выберите поле, которое не требует сериализации, используя вредное ключевое слово.

От вывода мы видим,При использовании переходных модифицированных свойств Java-последовательности игнорируют это поле, поэтому объект реорганизован, а атрибут, модифицированный переходным значением, является значением по умолчанию. Для опорных типов значение равно нуле; базовый тип, значение равно 0; логический тип, значение ложно.

Хотя использование транспортировки простое, это свойство полностью изолирована вне сериализации. Java предлагаетДополнительная пользовательская сериализация.Можно выполнить сериализацию управления или сериализованные данные могут быть закодированы.

Переписывая методы ImiteObject и ReadObject, вы можете выбрать, какие атрибуты нуждаются в сериализации, какие атрибуты не нужны. Если iPortObject сериализуется в определенном правиле, соответствующие ReadObject нуждаются в противоположных правилах для деактивации, чтобы правильно обратное секвенирование. Здесь имя изменено и зашифровано.

Когда поток сериализации неполный, метод readobjectNodata () может быть использован для правильной инициализации объекта на основе анти последовательности. Например, при использовании различных классов для получения обратных объектов SELECENTE или когда потомок сериализации подделан, система вызывает метод readobjectNodata () для инициализации объекта Anti-Selecente.

Более тщательная пользовательская сериализация

ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;

Writeereplace: Этот метод будет называться первым в сериализации, а затем вызовите метод IrouryObject. Этот метод может заменить любой объект вместо целевых объектов последовательности

ReadReSolve: замените анти-последовательность объектов во время обратной последовательности, и объектный объект немедленно отбрасывается. Этот метод называется после RedeObject.

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

ПРИМЕЧАНИЕ. Модификаторы ReadReSolve и Writereplace могут быть частными, защищенными, публичными, если родительский класс переписывает эти два метода, подклассы должны переписать в соответствии с их собственными потребностями, что, очевидно, не хороший дизайн. Как правило, рекомендуется переписать метод ReadReSolve для окончательных модифицированных классов; в противном случае переписать READRESOVE с использованием частных модификаций.

2, экстернализуемое: сила пользовательской сериализации

Реализация внешнего интерфейса, WriteeExternal, ReadExternal метод должен быть реализован.

ПРИМЕЧАНИЕ. Внешний интерфейс отличается от интерфейса серии, и интерфейс должен реализовывать два метода в интерфейсе для достижения пользовательской сериализации, что является обязательным; особое место должно обеспечить нерешительный конструктор пульфа, потому что в десериализации необходимо отражать, чтобы создать объект.

3, две сравнения последовательности

Внедрить сериализативный интерфейс Внедрить внешний интерфейс
Система автоматически хранит необходимую информацию Программист решит, какой информационный магазин
Встроенная поддержка Java, легко реализовать, нужно только реализовать интерфейс, без поддержки кода Два метода должны быть реализованы в интерфейсе
Небольшая производительность Небольшая производительность

Хотя экстернализуемый интерфейс принес определенные улучшения производительности, он также улучшил сложность, поэтому он обычно сериализуется путем реализации серии Serializable.

Третий, сериализованный номер версии SerialVersionUID

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

Java Serialization обеспечивает сериализованную версию номер частного статического окончательного длинного длинного SerialVersionud, только номер версии одинаковы, даже если сериализация свойства изменяются, объект может быть правильно напоминается.

Если десериализация используетсяНомер версии классаИспользуется в сериализацииНепоследовательный, Обратная последовательностьСообщите об инвалидной задаче.

Сериализованный номер версии может быть свободно указан. Если не указано, JVM вычисляет номер версии в соответствии с информацией класса, так как обновление класса, он не будет правильно изменен правильно; другой очевидной скрытой опасности номера версии Не способствует трансплантации JVM, возможно, файл класса не изменился, но правила, которые могут рассчитать различные JVMS, отличаются, которые также приведут к непризнанной последовательности.

Читайте также: