Модуль Pickle в Python

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

  • Кэшировать результаты вычислений на диск, чтобы избежать повторных вычислений
  • Сохранять пользовательскую конфигурацию и промежуточное состояние программы
  • Передача сложных объектов между разными процессами Python

pickleМодуль — это то, что Python предоставляет для решения этих задачОфициальное встроенное решение。

Pythonpickleмодуль — это модуль стандартной библиотеки для сериализации и десериализации объектов Python.

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

  • Сериализация (Pickling): преобразование объектов Python в последовательности байтов
  • Десериализация (Unpickling): преобразование последовательностей байтов обратно в объекты Python

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

Зачем использовать модуль Pickle?

  1. Сохранение данных: сохранение объектов Python в файлы, чтобы данные оставались доступными после закрытия программы.
  2. Передача данных: передача объектов Python по сети, например, передача данных в распределённых системах.
  3. Быстрое сохранение и загрузка:pickleМодуль может эффективно обрабатывать сложные структуры данных и подходит для сценариев, требующих быстрого сохранения и загрузки.

Типичные сценарии использования Pickle

pickleОн очень хорошо подходит для следующих сценариев:

  1. Локальное сохранение данных
  2. Сохранение и восстановление состояния выполнения программы
  3. Кэширование промежуточных результатов вычислений
  4. Межпроцессное взаимодействие Python (IPC)
  5. Сохранение моделей машинного обучения и данных признаков

Неподходящие сценарии:

  • Обмен данными между языками
  • Передача данных через интерфейс между фронтендом и бэкендом
  • Десериализация недоверенных источников данных

Какие объекты поддерживает Pickle?

1. Поддерживаемые типы объектов

Type Поддерживается?
int / float / bool / str Поддерживается
list / tuple / dict / set Поддерживается
Отсутствует Поддерживается
Экземпляры пользовательских классов Поддерживается
Вложенные структуры Поддерживается

Неподдерживаемые или нерекомендуемые объекты

  • Открытые файловые объекты
  • socket, подключения к базам данных
  • Ресурсы операционной системы
  • Объекты, зависящие от состояния среды выполнения

Импорт модуля

Использование модуля Pickle очень просто: достаточно импортировать его:

import pickle

Базовое использование модуля Pickle

1. Сериализация объектов

Используйтеpickle.dump()метод может сериализовать объекты Python и сохранить их в файл.

Пример

import pickle

# Создайте объект Python
data = {
    'name': 'Alice',
    'age': 25,
    'hobbies': ['reading', 'traveling']
}

# Сериализуйте объект и сохраните его в файл
with open('data.pkl', 'wb') as файл:
    pickle.dump(data, file)
  • 'wb'Указывает на открытие файла в режиме двоичной записи.
  • pickle.dump()будетdataОбъект сериализуется и записывается в файл.

2. Десериализация объектов

Используйтеpickle.load()метод может загружать и десериализовать объекты Python из файла.

Пример

import pickle

# Загрузка и десериализация объектов из файла
with open('data.pkl', 'rb') as файл:
    loaded_data = pickle.load(file)

print(loaded_data)
  • 'rb'Указывает на открытие файла в режиме бинарного чтения.
  • pickle.load()Считывает поток байтов из файла и десериализует его в объект Python.

3. Сериализация в байтовую строку

Если вы не хотите сохранять в файл, можно использовать pickle.dumps() для сериализации объекта в байтовую строку:

Пример

import pickle

data = [1, 2, 3, 4, 5]

# Сериализация в байтовую строку
byte_data = pickle.dumps(data)
print(byte_data)
# Вывод примерно такой: b'\x80\x04\x95\x0f\x00\x00\x00...'

4. Десериализация из байтовой строки

Используйте pickle.loads() для десериализации объектов из байтовой строки:

Пример

import pickle

byte_data = b'\x80\x04\x95\x0f\x00\x00\x00\x00\x00\x00\x00]\x94(K\x01K\x02K\x03K\x04K\x05e.'

# Десериализация из байтовой строки
original_data = pickle.loads(byte_data)
print(original_data)
# Вывод: [1, 2, 3, 4, 5]

5. Типы объектов, которые можно сериализовать

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

  • Базовые типы данных: целые числа, числа с плавающей запятой, строки, логические значения, None
  • Типы коллекций: списки, кортежи, словари, множества
  • Экземпляры пользовательских классов
  • Функции и классы (с определёнными ограничениями)

Пример

import pickle

# Сериализовать различные типы данных
numbers = [1, 2, 3]
text = "Hello, Pickle"
dictionary = {'key': 'value'}
tuple_data = (1, 2, 3)
set_data = {1, 2, 3}

# Поместить все данные в список
all_data = [numbers, text, dictionary, tuple_data, set_data]

# Сериализовать
with open('mixed_data.pkl', 'wb') as f:
    pickle.dump(all_data, f)

# Десериализовать
with open('mixed_data.pkl', 'rb') as f:
    loaded_data = pickle.load(f)
    print(loaded_data)

6. Сериализация пользовательских классов

Pickle хорошо справляется с экземплярами пользовательских классов:

Пример

import pickle

class Student:
    def __init__(self, name, age, grade):
        self.name = name
        self.age = age
        self.grade = grade
   
    def __repr__(self):
        return f"Student(name={self.name}, age={self.age}, grade={self.grade})"

# Создать экземпляр
student = Student("Li Si", 20, "Junior")

# Сериализовать
with open('student.pkl', 'wb') as f:
    pickle.dump(student, f)

# Десериализовать
with open('student.pkl', 'rb') as f:
    loaded_student = pickle.load(f)
    print(loaded_student)
    # Вывод: Student(name=Li Si, age=20, grade=Junior)

7. Сериализация нескольких объектов

Вы можете вызвать pickle.dump() несколько раз, чтобы сохранить несколько объектов:

Пример

import pickle

data1 = {'item': 'apple', 'count': 5}
data2 = ['banana', 'orange', 'grape']
data3 = 42

# Сохранить несколько объектов
with open('multiple.pkl', 'wb') as f:
    pickle.dump(data1, f)
    pickle.dump(data2, f)
    pickle.dump(data3, f)

# Чтение нескольких объектов (порядок должен быть согласован)
with open('multiple.pkl', 'rb') as f:
    loaded_data1 = pickle.load(f)
    loaded_data2 = pickle.load(f)
    loaded_data3 = pickle.load(f)
   
print(loaded_data1)
print(loaded_data2)
print(loaded_data3)

8. Примеры практического применения

Пример 1: Сохранение и загрузка конфигурации модели машинного обучения

Пример

import pickle

# Имитация конфигурации модели машинного обучения
model_config = {
    'model_type': 'RandomForest',
    'n_estimators': 100,
    'max_depth': 10,
    'trained_date': '2024-01-13',
    'accuracy': 0.95
}

# Сохранить конфигурацию
with open('model_config.pkl', 'wb') as f:
    pickle.dump(model_config, f)

# Загрузить конфигурацию
with open('model_config.pkl', 'rb') as f:
    config = pickle.load(f)
    print(f"Тип модели: {config['model_type']}")
    print(f"Точность: {config['accuracy']}")

Пример 2: Кэширование результатов вычислений

Пример

import pickle
import os

def expensive_computation(n):
    """Имитировать длительное вычисление"""
    result = sum(i ** 2 for i in range(n))
    return result

def compute_with_cache(n, cache_file='cache.pkl'):
    # Проверить, существует ли кэш
    if os.path.exists(cache_file):
        with open(cache_file, 'rb') as f:
            cache = pickle.load(f)
            if n in cache:
                print("Результат прочитан из кэша")
                return cache[n]
    else:
        cache = {}
   
    # Выполнить вычисление
    print("Выполняется расчёт...")
    result = expensive_computation(n)
   
    # Сохранить в кэш
    cache[n] = result
    with open(cache_file, 'wb') as f:
        pickle.dump(cache, f)
   
    return result

# Пример использования
print(compute_with_cache(1000000))  # При первом вызове будет вычислено
print(compute_with_cache(1000000))  # Во второй раз будет прочитано из кэша

Примечания о модуле Pickle

  1. Безопасность:pickleМодуль исполняет произвольный код во время десериализации, поэтому не загружайтеpickleданные из ненадёжных источников, чтобы избежать вредоносных атак.
  2. Совместимость:pickleСгенерированный поток байтов специфичен для Python, и могут возникнуть проблемы совместимости между разными версиями Python.
  3. Производительность: Для больших наборов данных,pickleсериализация и десериализация могут быть относительно медленными; можно рассмотреть использование более эффективных инструментов сериализации, таких какjsonилиmsgpack。

Расширенное использование: сериализация пользовательских объектов

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

Пример

import pickle

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __getstate__(self):
        # Пользовательская логика сериализации
        return {'name': self.name, 'age': self.age}

    def __setstate__(self, state):
        # Пользовательская логика десериализации
        self.name = state['name']
        self.age = state['age']

# Создать объект и сериализовать
person = Person('Bob', 30)
with open('person.pkl', 'wb') as файл:
    pickle.dump(person, file)

# Десериализовать объект
with open('person.pkl', 'rb') as файл:
    loaded_person = pickle.load(file)

print(loaded_person.name, loaded_person.age)

Общие методы модуля pickle

МетодОписаниеПример
pickle.dump(obj, file)Сериализовать объект и записать в файлpickle.dump(data, open('data.pkl', 'wb'))
pickle.load(file)Прочитать из файла и десериализовать объектdata = pickle.load(open('data.pkl', 'rb'))
pickle.dumps(obj)Сериализовать объект в байтовую строкуbytes_data = pickle.dumps([1, 2, 3])
pickle.loads(bytes)Десериализовать объект из байтовой строкиlst = pickle.loads(bytes_data)
pickle.HIGHEST_PROTOCOLНаивысшая доступная версия протокола (атрибут)pickle.dump(..., protocol=pickle.HIGHEST_PROTOCOL)
pickle.DEFAULT_PROTOCOLВерсия протокола по умолчанию (атрибут, обычно 4)pickle.dumps(obj, protocol=pickle.DEFAULT_PROTOCOL)

1. Сериализация объекта в файл

Пример

import pickle
data = {'name': 'Alice', 'age': 25}
with open('data.pkl', 'wb') as f:
    pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)

2. Десериализация из файла

Пример

with open('data.pkl', 'rb') as f:
    loaded_data = pickle.load(f)
print(loaded_data)  # Вывод: {'name': 'Alice', 'age': 25}

3. Сериализация в байтовую строку (передача по сети/кэш)

Пример

bytes_data = pickle.dumps([1, 2, 3], protocol=4)
restored_list = pickle.loads(bytes_data)

Версии протокола модуля pickle

Версия протоколаОписание
0Удобочитаемый формат ASCII (совместим с более старыми версиями)
1Двоичный формат (совместим с более старыми версиями)
2Python 2.3+: оптимизированная поддержка объектов классов
3Python 3.0+: протокол по умолчанию (не поддерживается в Python 2)
4Python 3.4+: поддерживает более крупные объекты и больше типов данных
5Python 3.8+: поддерживает оптимизацию памяти и совместное использование данных
Другие расширения