Pickle.dumps: примеры (PYTHON)

Сериализация объектов Python с помощью функции pickle.dumps
Раздел: Сериализация, Бинарная сериализация
pickle.dumps(obj, protocol, fix_imports): bytes

Описание функции pickle.dumps

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

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

Аргументы функции

  • obj (обязательный): Любой объект Python, подлежащий сериализации.
  • protocol (необязательный, целое число): Определяет версию протокола pickle. Допустимые значения: от 0 до 5. Чем выше число, тем новее протокол. По умолчанию используется протокол последней поддерживаемой версии Python, но для совместимости можно указать конкретный. Значение -1 эквивалентно использованию самого высокого доступного протокола.
  • fix_imports (необязательный, логический): При значении True (по умолчанию) и использовании протокола меньше 3, модуль пытается автоматически преобразовать имена модулей Python 2 в эквиваленты для Python 3.
  • buffer_callback (необязательный, вызываемый объект): Доступен с протокола 5. Позволяет обрабатывать буферы (например, объекты memoryview) отдельно от основного потока данных, что полезно для эффективной сериализации больших объектов.

Возвращаемое значение

Функция возвращает объект типа bytes, содержащий сериализованное представление исходного объекта. Эти байты можно сохранить или передать. Если используется buffer_callback, возвращается кортеж (bytes, список_буферов).

Базовые примеры использования

Пример сериализации простого объекта:

import pickle

simple_list = [1, 2, 3, {'key': 'value'}]
serialized = pickle.dumps(simple_list)
print(type(serialized))
print(serialized[:20], '...')
<class 'bytes'>
b'\x80\x04\x95\x19\x00\x00\x00\x00\x00\x00\x00]\x94(K\x01K\x02K\x03' ...

Пример с указанием протокола:

data = {'name': 'Alice', 'age': 30}
# Использование протокола 0 (человекочитаемый ASCII)
result_0 = pickle.dumps(data, protocol=0)
print('Protocol 0:', result_0[:50])

# Использование протокола 4 (Python 3.4+)
result_4 = pickle.dumps(data, protocol=4)
print('Protocol 4:', result_4[:50])
Protocol 0: b'(dp0\nVname\np1\nVAlice\np2\nsVage\np3\nI30\ns.'
Protocol 4: b'\x80\x04\x95\x1b\x00\x00\x00\x00\x00\x00\x00\x8c\x04name\x94\x8c\x05Alice\x94\x8c\x03age\x94K\x1e\x87\x94.'

Пример с пользовательским классом:

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

person = Person('Bob')
serialized_person = pickle.dumps(person)
print(serialized_person[:60])
b'\x80\x04\x95\x1f\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x06Person\x94\x93\x94)\x81\x94}\x94\x8c\x04name\x94\x8c\x03Bob\x94sb.'

Похожие функции в Python

  • pickle.dump(obj, file): Сериализует объект и записывает его в файловый объект. Используется при необходимости сохранить данные в файл.
  • json.dumps(): Сериализует объект в строку JSON. Поддерживает ограниченный набор типов данных (словари, списки, строки, числа, булевы значения, None). Формат текстовый и легко читаем, совместим с другими языками.
  • marshal.dumps(): Низкоуровневая сериализация, используемая в основном для байт-кода Python. Не рекомендуется для общих задач, так как не гарантирует стабильность между версиями Python.
  • yaml.dump() (из модуля PyYAML): Сериализация в формат YAML, который является человекочитаемым. Требует установки внешней библиотеки, медленнее pickle и json.
  • msgpack.packb() (из модуля msgpack): Бинарная сериализация, похожая на JSON, но более компактная и быстрая. Требует установки внешней библиотеки.

Выбор функции зависит от задачи: pickle.dumps() подходит для сериализации сложных объектов Python, когда данные будут использоваться только в Python. json.dumps() применяют для обмена данными с другими системами. yaml.dump() используют, когда важна читаемость конфигурационных файлов. msgpack.packb() выбирают для эффективного бинарного обмена данными между разными языками.

Альтернативы в других языках программирования

JavaScript (Node.js)

JSON.stringify(): Сериализует объект в строку JSON. Поддерживает ограниченные типы данных, как и в Python.

const obj = { name: "Alice", age: 30 };
const serialized = JSON.stringify(obj);
console.log(serialized);
{"name":"Alice","age":30}

Java

ObjectOutputStream и сериализация через интерфейс Serializable. Бинарный формат, специфичный для Java.

import java.io.*;

class Person implements Serializable {
    String name;
    int age;
}

Person person = new Person();
person.name = "Bob";
person.age = 25;

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(person);
byte[] serialized = baos.toByteArray();
System.out.println(Arrays.toString(Arrays.copyOf(serialized, 10)));
[-84, -19, 0, 5, 115, 114, 0, 4, 80, 101]

C#

BinaryFormatter.Serialize() (устарел в .NET 5+) или System.Text.Json.JsonSerializer.SerializeToUtf8Bytes() для JSON. Также доступны сторонние библиотеки, такие как MessagePack-CSharp.

using System.Text.Json;

var person = new { Name = "Charlie", Age = 35 };
byte[] serialized = JsonSerializer.SerializeToUtf8Bytes(person);
Console.WriteLine(Encoding.UTF8.GetString(serialized));
{"Name":"Charlie","Age":35}

PHP

serialize(): Создает хранимое представление значения. Формат специфичен для PHP.

$data = ['name' => 'David', 'age' => 40];
$serialized = serialize($data);
echo $serialized;
a:2:{s:4:"name";s:5:"David";s:3:"age";i:40;}

Golang

encoding/gob.Encode(): Бинарная сериализация, специфичная для Go. Также популярен encoding/json.Marshal() для JSON.

import "encoding/json"

type Person struct {
    Name string
    Age  int
}

p := Person{"Eve", 28}
serialized, _ := json.Marshal(p)
fmt.Println(string(serialized))
{"Name":"Eve","Age":28}

Отличия от Python

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

Типичные ошибки

Сериализация несериализуемых объектов

Некоторые объекты, например открытые файлы или сокеты, не могут быть сериализованы.

import pickle
import socket

s = socket.socket()
try:
    pickle.dumps(s)
except pickle.PicklingError as e:
    print(f'Ошибка: {e}')
Ошибка: Can't pickle <socket.socket ...>: it's not the same object as ...

Рекурсивные структуры данных

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

a = []
a.append(a)  # Список содержит сам себя
try:
    pickle.dumps(a)
except RecursionError as e:
    print(f'Ошибка: {e}')
Ошибка: maximum recursion depth exceeded while pickling an object

Проблемы с памятью при сериализации больших объектов

Функция dumps() возвращает весь результат в памяти, что для очень больших объектов может вызвать MemoryError. В таких случаях используют pickle.dump() с записью в файл.

Использование протокола, не поддерживаемого версией Python

try:
    # Попытка использовать протокол 5 в Python 3.7, где он недоступен
    data = pickle.dumps([1, 2, 3], protocol=5)
except ValueError as e:
    print(f'Ошибка: {e}')
Ошибка: unsupported pickle protocol: 5

Изменения в последних версиях Python

  • Python 3.8: Добавлен протокол 5, который поддерживает обработку буферов через аргумент buffer_callback и улучшенную сериализацию объектов, использующих __reduce_ex__().
  • Python 3.6: По умолчанию используется протокол 4 (ранее по умолчанию был протокол 3). Протокол 4 добавляет поддержку очень больших объектов, сериализации динамически создаваемых классов и улучшенную компрессию для малых целых чисел.
  • Python 3.4: Введен протокол 4 как экспериментальный. Добавлена поддержка сериализации memoryview.
  • Python 3.0: По умолчанию используется протокол 3, который является бинарным и несовместимым с Python 2.x. Удалена поддержка протоколов 1 и 2 как устаревших (но их можно использовать для обратной совместимости).

Для обеспечения максимальной совместимости между разными версиями Python, особенно при обмене данными, иногда целесообразно явно указывать более старый протокол (например, протокол 2 для совместимости с Python 2.7, если используется fix_imports=True).

Расширенные примеры

Использование buffer_callback (протокол 5)

Позволяет отдельно обрабатывать большие буферы данных, такие как массивы numpy.

Пример python
import pickle
import numpy as np

def buffer_callback(buf):
    print(f'Буфер размером {len(buf)} байт перехвачен')
    # В реальном приложении буфер можно обработать отдельно

arr = np.zeros((100, 100), dtype=np.float32)
data = {'meta': 'matrix', 'array': arr}
serialized, buffers = pickle.dumps(data, protocol=5, buffer_callback=buffer_callback)
print(f'Основные данные: {len(serialized)} байт')
print(f'Количество буферов: {len(buffers)}')
Буфер размером 40000 байт перехвачен
Основные данные: 99 байт
Количество буферов: 1

Сериализация лямбда-функций и функций, определенных в __main__

Такие функции сериализуются по имени, поэтому их десериализация возможна только в том же модуле.

Пример python
import pickle

square = lambda x: x ** 2
def cube(x):
    return x ** 3

funcs = {'square': square, 'cube': cube}
serialized = pickle.dumps(funcs)
print(serialized[:150])
b'\x80\x04\x95X\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x06square\x94\x93\x94\x8c\x08__main__\x94\x8c\x04cube\x94\x93\x94\x86\x94}\x94(\x8c\x06square\x94h\x00\x8c\x04cube\x94h\x02u.'

Сериализация с использованием __getstate__ и __setstate__

Эти методы позволяют контролировать процесс сериализации и десериализации для пользовательских классов.

Пример python
class SecureData:
    def __init__(self, secret):
        self.secret = secret
        self.public = "Это открытые данные"
    
    def __getstate__(self):
        # Сериализуем только публичные данные
        state = self.__dict__.copy()
        del state['secret']
        return state
    
    def __setstate__(self, state):
        # При десериализации восстанавливаем состояние
        self.__dict__.update(state)
        self.secret = "[СКРЫТО]"

obj = SecureData("пароль123")
serialized = pickle.dumps(obj)
new_obj = pickle.loads(serialized)
print(f'public: {new_obj.public}')
print(f'secret: {new_obj.secret}')
public: Это открытые данные
secret: [СКРЫТО]

Сравнение размеров при разных протоколах

Пример python
test_data = {i: str(i)*10 for i in range(1000)}
sizes = {}
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
    serialized = pickle.dumps(test_data, protocol=protocol)
    sizes[protocol] = len(serialized)
    print(f'Протокол {protocol}: {len(serialized)} байт')
Протокол 0: 68091 байт
Протокол 1: 58945 байт
Протокол 2: 58945 байт
Протокол 3: 58945 байт
Протокол 4: 57973 байт
Протокол 5: 57973 байт

питон pickle.dumps function comments

En
Pickle.dumps Serialize object to bytes