Pickle.dumps: примеры (PYTHON)
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.
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__
Такие функции сериализуются по имени, поэтому их десериализация возможна только в том же модуле.
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__
Эти методы позволяют контролировать процесс сериализации и десериализации для пользовательских классов.
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: [СКРЫТО]
Сравнение размеров при разных протоколах
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 байт