Рубрики
Без рубрики

Введение в модуль Python Pickle

Автор оригинала: Mateusz Dobrychlop.

Вступление

Маринование-популярный способ консервирования продуктов. Согласно Википедия , это тоже довольно древняя процедура – хотя происхождение маринования неизвестно, древние месопотамцы, вероятно, использовали этот процесс 4400 лет назад. Помещая продукт в определенный раствор, можно резко увеличить срок его хранения. Другими словами, это метод, который позволяет нам хранить пищу для последующего потребления.

Если вы являетесь разработчиком Python, то однажды вам может понадобиться способ хранения ваших объектов Python для последующего использования. Ну, а что, если я скажу вам, что вы тоже можете мариновать объекты Python?

Сериализация

Сериализация-это процесс преобразования объектов или структур данных в байтовые потоки или строки. Поток байтов – это, ну, поток байтов-один байт состоит из 8 битов нулей и единиц. Затем эти байтовые потоки могут быть легко сохранены или переданы. Это позволяет разработчикам сохранять, например, данные конфигурации или прогресс пользователя, а затем хранить их (на диске или в базе данных) или отправлять в другое место.

Объекты Python также могут быть сериализованы с помощью модуля под названием Pickle .

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

Травление (или сериализацию вообще) не следует путать со сжатием. Целью травления является перевод данных в формат, который может быть перенесен из оперативной памяти на диск. Сжатие, с другой стороны, представляет собой процесс кодирования данных с использованием меньшего количества битов (для экономии дискового пространства).

Сериализация особенно полезна в любом программном обеспечении, где важно иметь возможность сохранить некоторый прогресс на диске, выйти из программы и затем загрузить прогресс обратно после повторного открытия программы. Видеоигры могут быть наиболее интуитивным примером полезности сериализации, но есть много других программ, где сохранение и загрузка прогресса пользователя или данных имеет решающее значение.

Пикл против ДЖЕЙСОНА

Есть вероятность, что вы слышали о JSON (JavaScript Object Notation), который является популярным форматом, который также позволяет разработчикам сохранять и передавать объекты, закодированные в виде строк. Этот метод сериализации имеет некоторые преимущества перед травлением. Формат JSON удобочитаем для человека, не зависит от языка и работает быстрее, чем pickle.

Однако у него есть и некоторые важные ограничения. Самое главное, что по умолчанию только ограниченное подмножество встроенных типов Python может быть представлено JSON. С помощью Pickle мы можем легко сериализовать очень большой спектр типов Python и, что немаловажно, пользовательские классы. Это означает, что нам не нужно создавать пользовательскую схему (как мы делаем для JSON) и писать подверженные ошибкам сериализаторы и парсеры. Все тяжелые подъемы делаются за вас с Рассолом.

Что можно мариновать и не мариновать

Следующие типы могут быть сериализованы и десериализованы с помощью модуля Pickle:

  • Все собственные типы данных, поддерживаемые Python (booleans, None, integers, floats, complex numbers, strings, bytes, byte arrays)
  • Словари, наборы, списки и кортежи – до тех пор, пока они содержат маринуемые объекты
  • Функции и классы, определенные на верхнем уровне модуля

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

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

Также очень важно отметить, что маринованные предметы могут быть использованы злонамеренно. Например, распаковка данных из ненадежного источника может привести к выполнению вредоносного фрагмента кода.

Выбор списка Python

Следующий очень простой пример показывает основы использования модуля Pickle в Python 3 :

import pickle

test_list = ['cucumber', 'pumpkin', 'carrot']

with open('test_pickle.pkl', 'wb') as pickle_out:
    pickle.dump(test_list, pickle_out)

Во-первых, мы должны импортировать модуль pickle , что делается в строке 1. В строке 3 мы определяем простой, трехэлементный список, который будет замаринован.

В строке 5 мы указываем, что имя нашего выходного файла pickle будет test_pickle.pkl . Используя опцию wb , мы сообщаем программе, что хотим записать ( w ) двоичные данные ( b ) внутри нее (потому что мы хотим создать поток байтов). Обратите внимание, что расширение pkl не является необходимым – мы используем его в этом уроке, потому что это расширение включено в документацию Python.

В строке 6 мы используем метод pickle.dump() для маринования нашего тестового списка и хранения его внутри test_pickle.pkl файл.

Я рекомендую вам попробовать открыть сгенерированный файл pickle в вашем текстовом редакторе. Вы быстро заметите, что поток байтов определенно не является удобочитаемым форматом.

Распаковка списка Python

Теперь давайте распакуем содержимое файла test pickle и вернем наш объект в его первоначальную форму.

import pickle

with open('test_pickle.pkl', 'rb') as pickle_in:
    unpickled_list = pickle.load(pickle_in)

print(unpickled_list)

Как видите, эта процедура не сложнее, чем когда мы выбирали объект. В строке 3 мы открываем наш test_pickle.pkl файл снова, но на этот раз наша цель-прочитать ( r ) двоичные данные ( b ), хранящиеся в нем.

Далее, в строке 5, мы используем pickle.load() метод распаковки нашего списка и сохранения его в переменной unpickled_list .

Затем вы можете распечатать содержимое списка, чтобы убедиться, что он идентичен списку, который мы замариновали в предыдущем примере. Вот результат выполнения приведенного выше кода:

$ python unpickle.py
['cucumber', 'pumpkin', 'carrot']

Травление и распаковка пользовательских объектов

Как я уже упоминал ранее, используя Pickle, вы можете сериализовать свои собственные пользовательские объекты. Взгляните на следующий пример:

import pickle

class Veggy():
    def __init__(self):
        self.color = ''
    def set_color(self, color):
        self.color = color

cucumber = Veggy()
cucumber.set_color('green')

with open('test_pickle.pkl', 'wb') as pickle_out:
    pickle.dump(cucumber, pickle_out)

with open('test_pickle.pkl', 'rb') as pickle_in:
    unpickled_cucumber = pickle.load(pickle_in)

print(unpickled_cucumber.color)

Как видите, этот пример почти так же прост, как и предыдущий. Между строками 3 и 7 мы определяем простой класс, который содержит один атрибут и один метод, который изменяет этот атрибут. В строке 9 мы создаем экземпляр этого класса и сохраняем его в переменной cucumber , а в строке 10 устанавливаем его атрибут color на “зеленый”.

Затем, используя те же функции, что и в предыдущем примере, мы маринуем и распаковываем наш недавно созданный объект cucumber . Выполнение приведенного выше кода приводит к следующему результату:

$ python unpickle_custom.py
green

Помните, что мы можем распаковать объект только в среде, где класс Veggy либо определен, либо импортирован. Если мы создадим новый скрипт и попытаемся распаковать объект без импорта класса Veggie , то получим “AttributeError”. Например, выполните следующий сценарий:

import pickle

with open('test_pickle.pkl', 'rb') as pickle_in:
    unpickled_cucumber = pickle.load(pickle_in)

print(unpickled_cucumber.color)

В выводе приведенного выше скрипта вы увидите следующую ошибку:

$ python unpickle_simple.py
Traceback (most recent call last):
  File "", line 2, in 
    unpickled_cucumber = pickle.load(pickle_in)
AttributeError: Can't get attribute 'Veggy' on 

Вывод

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

Маринование имеет некоторые недостатки, самым большим из которых может быть тот факт, что вы можете распаковать свои данные только с помощью Python – если вам нужно кросс-языковое решение, JSON определенно является лучшим вариантом. И, наконец, помните, что соленые огурцы могут использоваться для переноса кода, который вы не обязательно хотите выполнять. Как и в случае с маринованной пищей, пока вы получаете маринованные огурцы из надежных источников, вы должны быть в порядке.