Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Python
Code

Сериализация и десериализация объектов Python: часть 2

by
Difficulty:IntermediateLength:MediumLanguages:

Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)

Это вторая часть учебника по сериализации и десериализации объектов Python. В первой части вы научились основам, а затем нырнули во всевозможные проблемы с Pickle и JSON.

В этой части вы исследуете YAML (убедитесь, что у вас есть пример выполнения из первой части), обсудите вопросы производительности и безопасности, просмотрите дополнительные форматы сериализации и, наконец, узнайте, как выбрать правильную схему.

YAML

YAML - мой любимый формат. Это удобный для пользователя формат сериализации данных. В отличие от Pickle и JSON, он не является частью стандартной библиотеки Python, поэтому вам необходимо установить его:

pip install yaml

Модуль yaml имеет только функции load() и dump(). По умолчанию они работают со строками loads() и dumps(), но могут принимать второй аргумент, который является открытым потоком, а затем может выгружать/загружать файлы из/в файлы.

Обратите внимание, как читаемый YAML сравнивается с Pickle или даже JSON. И теперь для самой крутой части о YAML: он понимает объекты Python! Нет необходимости в пользовательских кодировщиках и декодерах. Вот комплексная сериализация / десериализация с использованием YAML:

Как вы можете видеть, YAML имеет свои собственные обозначения для тегов объектов Python. Вывод по-прежнему очень читабельный для человека. Объект datetime не требует специальной маркировки, потому что YAML по своей сути поддерживает объекты datetime.

Производительность

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

Но, предполагая, что вы профилировали свою систему и обнаружили, что сериализация и / или десериализация вызывают проблемы с производительностью, вот что нужно решить.

Это два аспекта производительности: насколько быстро вы можете сериализовать / десериализовать и насколько велико сериализованное представление?

Чтобы проверить производительность различных форматов сериализации, я создам довольно большую структуру данных и сериализую / десериализую ее с помощью Pickle, YAML и JSON. Список big_data содержит 5000 сложных объектов.

Pickle

Я буду использовать IPython здесь для его удобной функции %timeit, которая измеряет время выполнения.

По умолчанию занимает 83,1 миллисекунды для сериализации и 29,2 миллисекунды для десериализации, а сериализованный размер - 747 328 байт.

Давайте попробуем с самым высоким протоколом.

Интересные результаты. Время сериализации сократилось до 21,2 миллисекунды, но время десериализации немного увеличилось до 25,2 миллисекунд. Сериализованный размер значительно сократился до 394 350 байтов (52%).

JSON

Хорошо. Производительность кажется немного хуже, чем Pickle для кодирования, но гораздо хуже для декодирования: в 6 раз медленнее. В чем дело? Это артефакт функции object_hook, который нужно запустить для каждого словаря, чтобы проверить, нужно ли его преобразовывать в объект. Выполнение без хука объекта происходит намного быстрее.

Урок здесь заключается в том, что при сериализации и десериализации в JSON очень тщательно учитывайте любые пользовательские кодировки, поскольку они могут существенно повлиять на общую производительность.

YAML

Хорошо. YAML действительно, очень медленный. Но обратите внимание на что-то интересное: сериализованный размер составляет всего лишь 200 091 байт. Гораздо лучше, чем у Pickle и JSON. Давайте заглянем в реальную быстроту:

YAML здесь очень умный. Он определил, что все 5000 dicts используют одно и то же значение для ключа «a», поэтому он сохраняет его только один раз и ссылается на него, используя *id001 для всех объектов.

Безопасность

Безопасность часто является серьезной проблемой. Pickle и YAML, благодаря построению объектов Python, уязвимы для атак на выполнение кода. Умело отформатированный файл может содержать произвольный код, который будет выполняться Pickle или YAML. Не нужно беспокоиться. Это по дизайну и задокументировано в документации Pickle:

Предупреждение. Модуль pickle не предназначен для защиты от ошибочных или вредоносных данных. Никогда не распечатывайте данные, полученные от ненадежного или не прошедшего проверку подлинности источника.

Как и в документации YAML:

Предупреждение. Небезопасно вызывать yaml.load с любыми данными, полученными от ненадежного источника! yaml.load так же эффективен, как pickle.load, и поэтому может вызывать любую функцию Python.

Вам просто нужно понять, что вы не должны загружать сериализованные данные, полученные из ненадежных источников, используя Pickle или YAML. JSON в порядке, но опять же, если у вас есть пользовательские кодировщики / декодеры, чем вы можете быть выставлены тоже.

Модуль yaml предоставляет yaml.safe_load() функция, которая будет загружать только простые объекты, но тогда вы потеряете много мощности YAML и, возможно, захотите использовать JSON.

Другие форматы

Существует много других форматов сериализации. Вот несколько из них.

Protobuf

Protobuf или протокольные буферы - это формат обмена данными Google. Он реализован в C ++, но имеет привязки Python. Он имеет сложную схему и эффективно упаковывает данные. Очень мощный, но не очень простой в использовании.

MessagePack

MessagePack - еще один популярный формат сериализации. Он также бинарный и эффективный, но в отличие от Protobuf он не требует схемы. У этого есть система типов, которая похожа на JSON, но немного богаче. Ключи могут быть любого типа, а не только строки и строки, отличные от UTF8.

CBOR

CBOR означает представление сжатого двоичного объекта. Опять же, он поддерживает модель данных JSON. CBOR не так хорошо известен как Protobuf или MessagePack, но интересен по двум причинам:

  1. Это официальный интернет-стандарт: RFC 7049.
  2. Он был разработан специально для Internet of Things (IoT).

Какой выбрать?

Это большой вопрос. С таким количеством вариантов, как вы выбираете? Рассмотрим различные факторы, которые следует учитывать:

  1. Должен ли сериализованный формат быть удобочитаемым и / или редактируемым человеком?
  2. Будет ли сериализованный контент получен от ненадежных источников?
  3. Является ли сериализация / десериализация узким местом производительности?
  4. Нужно ли сериализованные данные обмениваться с средами, отличными от Python?

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

Автоматическое сохранение локального состояния программы Python

Используйте pickle (cPickle) здесь с HIGHEST_PROTOCOL. Это быстро, эффективно и может хранить и загружать большинство объектов Python без специального кода. Он также может использоваться как локальный постоянный кеш.

Файлы конфигурации

Определенно YAML. Ничто не сравнится с его простотой для чего-либо, что люди должны читать или редактировать. Он успешно используется Ansible и многими другими проектами. В некоторых ситуациях вы можете использовать прямые модули Python в качестве файлов конфигурации. Это может быть правильный выбор, но тогда это не сериализация, и это действительно часть программы, а не отдельный файл конфигурации.

Веб-интерфейсы

JSON - явный победитель здесь. В наши дни веб-API чаще всего используются веб-приложениями JavaScript, которые говорят на JSON изначально. Некоторые веб-API могут возвращать другие форматы (например, csv для плотных табличных наборов результатов), но я бы сказал, что вы можете упаковать данные csv в JSON с минимальными накладными расходами (нет необходимости повторять каждую строку как объект со всеми именами столбцов).

Высокопроизводительная / малозатухающая широкомасштабная связь

Используйте один из двоичных протоколов: Protobuf (если вам нужна схема), MessagePack или CBOR. Выполните собственные тесты, чтобы проверить производительность и представительную мощность каждого параметра.

Заключение

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

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

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.