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 сохраняет не только данные, но и информацию о типе объекта, включая его класс и модуль, что позволяет восстановить объект в точности с его исходным поведением.
Процесс сериализации включает:
- Определение протокола — выбор версии формата (от 0 до 5).
- Рекурсивный обход — для каждого объекта записывается его тип, значение и ссылки на вложенные объекты.
- Кодирование в байты — результат записывается в бинарный файл или поток.
Десериализация (unpickling) выполняет обратные действия: читает байтовый поток, восстанавливает объекты и их связи, вызывая конструкторы классов при необходимости.
Протоколы pickle
Pickle поддерживает несколько протоколов, различающихся по эффективности, совместимости и поддерживаемым возможностям:
| Протокол | Версия Python | Особенности |
|---|---|---|
| 0 | 1.4+ | Текстовый формат, читаемый человеком, медленный, неэффективный |
| 1 | 1.4+ | Бинарный формат, эффективнее протокола 0 |
| 2 | 2.3+ | Поддержка классов нового стиля, улучшенная производительность |
| 3 | 3.0+ | Протокол по умолчанию в Python 3, несовместим с Python 2 |
| 4 | 3.4+ | Поддержка очень больших объектов, вложенных структур, улучшенная работа с памятью |
| 5 | 3.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 может сериализовать даже функции и классы, но только если они определены на верхнем уровне модуля (глобально).
Источники
- Документация Python: модуль
pickle(Python 3.12). - PEP 574 — Pickle protocol 5 with out-of-band data.
- Лутц М. «Изучаем Python», 5-е издание, глава 9.
- Рейтц К. «Python. К вершинам мастерства», глава 7.
- Статья «Pickle: The Not-So-Simple Serialization» на Real Python.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →