Работа с файлами и сериализацией: pickle, shelve, marshal


Зачем нужна сериализация? 🤔

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

Представьте, что ваш объект — это сложный LEGO-домик. Сериализация аккуратно разбирает его, упаковывает в коробку (файл), а десериализация — снова собирает домик из деталей!


📦 Модуль pickle — ваш универсальный упаковщик

Стандартный модуль pickle — самый популярный инструмент для сериализации в Python. Он умеет работать практически с любыми объектами!

Основные методы:

  • pickle.dump(obj, file) — сохраняет объект в файл
  • pickle.load(file) — загружает объект из файла
  • pickle.dumps(obj) — возвращает сериализованный объект как bytes
  • pickle.loads(bytes) — восстанавливает объект из bytes
import pickle

# Сохраняем список в файл
data = {'name': 'Alice', 'age': 25, 'pets': ['cat', 'dog']}
with open('data.pickle', 'wb') as f:
    pickle.dump(data, f)

# Загружаем обратно
with open('data.pickle', 'rb') as f:
    loaded_data = pickle.load(f)

print(loaded_data)  # {'name': 'Alice', 'age': 25, 'pets': ['cat', 'dog']}

🔐 Важно: pickle небезопасен! Загружайте данные только из доверенных источников.


🗄️ Модуль shelve — как словарь, но в файле

Если вам нужно хранить много данных с быстрым доступом по ключу, shelve — отличное решение. По сути, это персистентный словарь!

import shelve

# Записываем данные
with shelve.open('mydata') as db:
    db['user1'] = {'name': 'Bob', 'score': 100}
    db['user2'] = {'name': 'Alice', 'score': 200}

# Читаем позже
with shelve.open('mydata') as db:
    print(db['user1'])  # {'name': 'Bob', 'score': 100}

✨ Особенности:

  • Ключи должны быть строками
  • Значения — любые объекты, поддерживаемые pickle
  • Автоматически создает несколько файлов для хранения данных

🚀 Модуль marshal — для внутренних нужд Python

Этот модуль используется в основном для сериализации байт-кода Python. Он быстрее pickle, но имеет ограничения:

import marshal

data = [1, 2, 3, 'hello']
serialized = marshal.dumps(data)
restored = marshal.loads(serialized)

print(restored)  # [1, 2, 3, 'hello']

⚠️ Осторожно:

  • Не гарантирует совместимость между версиями Python
  • Не подходит для сложных объектов
  • Документация прямо говорит: "Не используйте для сериализации произвольных данных"

🏆 Какой модуль выбрать?

Вот простая шпаргалка:

Критерий pickle shelve marshal
Универсальность ★★★★★ ★★★★☆ ★★☆☆☆
Скорость ★★★☆☆ ★★★☆☆ ★★★★★
Безопасность ★☆☆☆☆ ★☆☆☆☆ ★★★☆☆
Простота ★★★★☆ ★★★★★ ★★★☆☆

Для большинства задач подходит pickle. Нужно хранить много данных с доступом по ключу — выбирайте shelve. А marshal лучше оставить для специальных случаев.


💡 Продвинутые техники

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

pickle умеет работать с пользовательскими классами, если они определены в модуле:

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

person = Person('Alice', 30)
with open('person.pickle', 'wb') as f:
    pickle.dump(person, f)

Сжатие данных

Комбинируйте pickle с модулем gzip для экономии места:

import gzip

data = [i**2 for i in range(1000)]
with gzip.open('data.pgz', 'wb') as f:
    pickle.dump(data, f)

🛠️ Реальный пример: кэширование функций

Давайте применим знания на практике — реализуем простой кэш:

import pickle
from functools import wraps
from pathlib import Path

def cache_to_file(filename):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            cache_file = Path(filename)
            if cache_file.exists():
                with open(cache_file, 'rb') as f:
                    return pickle.load(f)

            result = func(*args, **kwargs)
            with open(cache_file, 'wb') as f:
                pickle.dump(result, f)
            return result
        return wrapper
    return decorator

@cache_to_file('factorial_cache.pickle')
def factorial(n):
    return 1 if n < 2 else n * factorial(n-1)

Теперь результаты вычислений будут сохраняться между запусками программы!


🚨 Ошибки и как их избежать

  1. Смешивание режимов файлов
    Всегда открывайте файлы в правильном режиме:
    'wb' для записи, 'rb' для чтения в pickle
    ❌ Использование текстового режима ('w', 'r') вызовет ошибку

  2. Бесконечная рекурсия
    При сериализации объектов с циклическими ссылками используйте:
    python pickle.dump(obj, file, protocol=pickle.HIGHEST_PROTOCOL)

  3. Совместимость версий
    Для кросс-версионной совместимости используйте протокол 4:
    python pickle.dumps(obj, protocol=4)


🔍 Дополнительные ресурсы

Для тех, кто хочет копнуть глубже:
- Официальная документация Python по pickle и shelve
- Видео Данилы Бежина о сериализации и JSON
- Модуль json для работы с текстовыми форматами (альтернатива pickle)

Скрыть рекламу навсегда

📘 VK Видео — обучение без ограничений

Все уроки доступны без VPN, без блокировок и зависаний.

Можно смотреть с телефона, планшета или компьютера — в любое время.

▶️ Смотреть на VK Видео