Открыть сервис

Python Pickle

Pickle — это модуль стандартной библиотеки языка программирования Python, предназначенный для сериализации и десериализации объектов Python, то есть для преобразования произвольной структуры данных (объекта) в байтовый поток (сериализация) и обратного восстановления объекта из этого потока (десериализация). Процесс сериализации с помощью pickle часто называют «упаковкой» (pickling), а обратный — «распаковкой» (unpickling). Модуль позволяет сохранять сложные иерархии объектов, включая вложенные списки, словари, пользовательские классы и их экземпляры, в файл или передавать их по сети.

История и происхождение

Модуль pickle был представлен в Python ещё в ранних версиях (начиная с Python 1.4, 1996 год) как часть стандартной библиотеки. Его название происходит от английского глагола «to pickle» — мариновать, консервировать, что метафорически отражает процесс сохранения объекта в «рассоле» байтов. Разработчики языка стремились создать простой и надёжный способ сохранения состояния объектов без необходимости написания собственных процедур сериализации.

С годами модуль эволюционировал. В Python 2 появился протокол 2, поддерживающий классы нового стиля. В Python 3 был добавлен протокол 3, который стал протоколом по умолчанию, а также протокол 4 (Python 3.4) с поддержкой очень больших объектов и вложенных структур. В Python 3.8 был представлен протокол 5, оптимизированный для работы с буферами данных и ускорения сериализации массивов. Несмотря на появление альтернативных библиотек сериализации (например, JSON, YAML, msgpack), pickle остаётся стандартным инструментом для внутреннего обмена данными в Python-приложениях.

Принцип работы

Pickle преобразует произвольный объект Python в последовательность байтов, используя рекурсивный обход его атрибутов и структуры. В отличие от текстовых форматов (JSON), pickle сохраняет не только данные, но и информацию о типе объекта, включая его класс и модуль, что позволяет восстановить объект в точности с его исходным поведением.

Процесс сериализации включает:

  1. Определение протокола — выбор версии формата (от 0 до 5).
  2. Рекурсивный обход — для каждого объекта записывается его тип, значение и ссылки на вложенные объекты.
  3. Кодирование в байты — результат записывается в бинарный файл или поток.

Десериализация (unpickling) выполняет обратные действия: читает байтовый поток, восстанавливает объекты и их связи, вызывая конструкторы классов при необходимости.

Протоколы pickle

Pickle поддерживает несколько протоколов, различающихся по эффективности, совместимости и поддерживаемым возможностям:

ПротоколВерсия PythonОсобенности
01.4+Текстовый формат, читаемый человеком, медленный, неэффективный
11.4+Бинарный формат, эффективнее протокола 0
22.3+Поддержка классов нового стиля, улучшенная производительность
33.0+Протокол по умолчанию в Python 3, несовместим с Python 2
43.4+Поддержка очень больших объектов, вложенных структур, улучшенная работа с памятью
53.8+Оптимизация для массивов и буферов данных (PEP 574)

По умолчанию в Python 3.x используется протокол 3. Для максимальной производительности и совместимости с новыми возможностями рекомендуется протокол 4 или 5.

Основные функции модуля

Модуль pickle предоставляет несколько ключевых функций и классов:

  • pickle.dump(obj, file, protocol=None) — сериализует объект obj и записывает его в открытый файловый объект file. Параметр protocol задаёт версию протокола.
  • pickle.dumps(obj, protocol=None) — возвращает байтовую строку, представляющую сериализованный объект.
  • pickle.load(file) — читает байтовый поток из файлового объекта и восстанавливает объект.
  • pickle.loads(data) — восстанавливает объект из байтовой строки.
  • pickle.Pickler(file, protocol) — класс для создания пользовательских сериализаторов.
  • pickle.Unpickler(file) — класс для создания пользовательских десериализаторов.

Пример базового использования:

```python import pickle

Сериализация

data = {'name': 'Alice', 'age': 30, 'scores': [95, 87, 92]} with open('data.pkl', 'wb') as f: pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)

Десериализация

with open('data.pkl', 'rb') as f: restored = pickle.load(f) print(restored) # {'name': 'Alice', 'age': 30, 'scores': [95, 87, 92]} ```

Поддерживаемые типы данных

Pickle может сериализовать большинство встроенных типов Python, включая:

  • Числа: int, float, complex, bool
  • Строки: str, bytes
  • Коллекции: list, tuple, dict, set, frozenset
  • Специальные типы: None, slice, range
  • Пользовательские классы: экземпляры классов, определённых пользователем, при условии, что класс определён на момент десериализации
  • Встроенные классы: исключения, функции (ограниченно), модули (ограниченно)

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

Ограничения и безопасность

Проблемы безопасности

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

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

Рекомендация: никогда не загружайте pickle-данные из ненадёжных источников (например, из интернета, от пользователей или из непроверенных файлов). Для безопасного обмена данными используйте текстовые форматы (JSON, YAML) или специализированные библиотеки с поддержкой проверки подписей.

Совместимость

Pickle-файлы не являются кроссплатформенными в полном смысле. Сериализованные данные могут быть несовместимы между разными версиями Python (особенно между Python 2 и Python 3) или при изменении кода классов. Если класс был изменён (добавлены или удалены атрибуты), десериализация старого файла может привести к ошибке или некорректному состоянию объекта.

Размер и производительность

Pickle создаёт бинарные файлы, которые обычно компактнее текстовых форматов, но могут быть больше, чем специализированные бинарные форматы (например, Protocol Buffers). Производительность сериализации и десериализации зависит от сложности объекта и выбранного протокола. Протоколы 4 и 5 значительно быстрее и эффективнее для больших данных.

Применение

Несмотря на проблемы безопасности, pickle широко используется в Python-экосистеме для внутренних целей:

  • Сохранение состояния приложений — например, кэширование результатов вычислений, сохранение настроек или промежуточных данных.
  • Передача данных между процессами — в многопроцессорных приложениях (модуль multiprocessing) pickle используется для сериализации аргументов и результатов при передаче между процессами.
  • Хранение моделей машинного обучения — библиотеки scikit-learn, XGBoost и другие используют pickle для сохранения обученных моделей.
  • Работа с базами данных — некоторые ORM (например, SQLAlchemy) используют pickle для хранения сложных структур в полях БД.
  • Кэширование — модуль functools.lru_cache и библиотеки кэширования (например, redis) часто используют pickle для сериализации ключей и значений.

Альтернативы

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

ФорматПреимуществаНедостатки
JSONБезопасен, читаем человеком, кроссплатформенныйНе поддерживает пользовательские классы, ограниченные типы данных
YAMLЧитаемость, поддержка сложных структурМедленнее JSON, может быть небезопасен при использовании yaml.load
MessagePackКомпактный бинарный формат, быстрыйМеньше поддержки в Python, нет встроенной поддержки классов
Protocol BuffersВысокая производительность, строгая типизацияТребует определения схемы, сложнее в использовании
dillРасширенная версия pickle, сериализует больше типовТе же проблемы безопасности

Интересные факты

  • Название «pickle» было выбрано в шутку разработчиками Python, так как процесс сохранения объекта напоминает консервирование огурцов.
  • Pickle является частью стандартной библиотеки Python, что делает его доступным без установки дополнительных пакетов.
  • В Python 3 протокол 2 и ниже считаются устаревшими и не рекомендуются к использованию.
  • Существует специальная утилита pickletools для анализа содержимого pickle-файлов и отладки.
  • Pickle может сериализовать даже функции и классы, но только если они определены на верхнем уровне модуля (глобально).

Источники

  1. Документация Python: модуль pickle (Python 3.12).
  2. PEP 574 — Pickle protocol 5 with out-of-band data.
  3. Лутц М. «Изучаем Python», 5-е издание, глава 9.
  4. Рейтц К. «Python. К вершинам мастерства», глава 7.
  5. Статья «Pickle: The Not-So-Simple Serialization» на Real Python.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →