Консервация объектов в Python

    В определенный момент любому Питон-программисту понадобится запаковать какой-то объект и спрятать его до лучших времен. Скажем, в config-файл. Или передать через сокет. Как это сделать? Разумеется, можно написать небольшой класс, который будет генерировать и парсить XML-код (кстати, следующая статья как раз будет об этом), но это — слишком большая морока.

    Нет! Наш выбор — Pickle!

    Преамбула


    Pickle (англ. консервировать, мариновать) — модуль сериализации и десериализации объектов в Питоне для последующей их передачи.

    Какие типы данных Pickle умеет запаковывать?
    • None, True, False
    • Строки (обычные или Юникод)
    • Стандартные числовые типы данных
    • Словари, списки, кортежи
    • Функции
    • Классы
    Но есть одна маленькая деталь. По началу вы будете вполне довольны работой этого модуля, но позже, когда будете его использовать на high-load проектах, начнете замечать, что консервирование данных занимает больше времени, чем хотелось бы. Эту проблему решили тем, что был написан подобный модуль, но уже не на Питоне, а на С, что ускорило его производительность в тысячи раз (по заявлению разработчиков). Да, иногда модули, написанные на С, работают быстрее их питоновских аналогов, но тут есть тонкости, в которые в этой статье я позволю себе не углубляться.

    Сами создатели Питона в официальной документации советуют использовать cPickle, а чтобы долго не модифицировать программу, можно подключить cPickle так:

    import cPickle as pickle

    Основы


    Как использовать консервацию объектов? У вас есть два варианта: либо консервировать объект в строку (которую можно передать через сокет, например) либо сразу в файл.

    Есть три протокола консервации:
    • Версия 0, стандартный ASCII протокол. Его следует использовать только для совместимости с ранними версиями Питона.
    • Версия 1 — примерно то же самое, используется для совместимости со старыми версиями Питона.
    • Версия 2 впервые внедрена в версии 2.3, она лучше всего запаковывает объекты, написанные в современном синтаксисе, я рекомендую использовать именно её.
    Консервирование объекта в строку:

    import cPickle as pickle
    obj = {"one": 123, "two": [1, 2, 3]}
    output = pickle.dumps(obj, 2)


    Как видите, ничего сложного, объект готов к отправке.
    Теперь нужно его распаковать назад. Это еще проще:

    obj = pickle.loads(output)

    Протокол консервирования определяется автоматически.
    Давайте попробуем запаковать объект в файл.

    import cPickle as pickle
    obj = {"one": 123, "two": [1, 2, 3]}
    output = open('data.pkl', 'wb')
    pickle.dump(obj, output, 2)
    output.close()


    Обратите внимание, что режим записи в файл должен обязательно быть wb, то есть перезапись файла в бинарном режиме. Для чтения режим должен быть rb:

    import cPickle as pickle
    input = open('data.pkl', 'rb')
    obj = pickle.load(input)
    input.close()


    Спасибо за внимание. В следующий раз я бы хотел поговорить об особенностях создания и парсинга XML-данных в Питоне.
    Метки:
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 45
    • +2
      как-то банально.

      статья о консервации объектов и ни слова не сказано про pickle protocol.

      у нас объекты это только dict?
      • 0
        Возможно, я чего-то не допонимаю, но про пикл протоколы я рассказал.
        Добавил кортежи.
        • +2
          как запиклить кастомный объект? как определяется может ли объект пиклиться?
          • 0
            Запиклится объект или нет — можно выяснить лишь попытавшись запиклить его. Если пикл прошел удачно (т. е. не вылезли ошибки), то и всё остальное тоже будет в порядке.
            • 0
              хорошо, а как добавить поддержку пиклинга в свой объект?
              • 0
                я в общем-то всё время об этом www.python.org/doc/2.2.3/lib/pickle-protocol.html
                • 0
                  не обязательно, можно «запиклить» объект в файл без ошибок, но он не откроется с другого скрипта если там сохранялся объект
              • 0
                какие требования к неймспейсу когда ты пиклишь и распикливаешь свои объекты?

                много в общем вопросов за кадром осталось.
                • 0
                  Ограничения по неймспейсам такие же, как и в самом языке (зарезервированные слова и т. д.)
                  • 0
                    Note that functions (built-in and user-defined) are pickled by ``fully qualified'' name reference, not by value. This means that only the function name is pickled, along with the name of module the function is defined in. Neither the function's code, nor any of its function attributes are pickled. Thus the defining module must be importable in the unpickling environment, and the module must contain the named object, otherwise an exception will be raised3.6.

                    Similarly, classes are pickled by named reference, so the same restrictions in the unpickling environment apply. Note that none of the class's code or data is pickled, so in the following example the class attribute attr is not restored in the unpickling environment:

                    class Foo:
                    attr = 'a class attr'

                    picklestring = pickle.dumps(Foo)

                    These restrictions are why picklable functions and classes must be defined in the top level of a module.

                    Similarly, when class instances are pickled, their class's code and data are not pickled along with them. Only the instance data are pickled. This is done on purpose, so you can fix bugs in a class or add methods to the class and still load objects that were created with an earlier version of the class. If you plan to have long-lived objects that will see many versions of a class, it may be worthwhile to put a version number in the objects so that suitable conversions can be made by the class's __setstate__() method.
                    • 0
                      Особой нужды паковать классы я не вижу, но не исключаю, что такая возможность понадобится.

                      Лично я запаковываю исключительно массивы или словари (скажем, файл локализации или индекс файлов).
            • 0
              умные люди говорят что пикл — небезопасно.
              • 0
                Я не делал акценты на безопасности пикла, а лишь рассказал о некоторых возможностях его использования.

                Кстати, в чем заключается эта небезопасность?
            • 0
              Сможет сериализовать граф?
              • 0
                Что он из себя представляет? Если это образование из типов, которые я описал выше, то должен. Вообще единственное ограничение, которое я нашел в официальной документации — это функции с глубокой рекурсией.
              • +3
                Тема сериализации не раскрыта.

                Начнем с того, что не указана цель сериализации. Иметь бинарные конфиги — моветон. Хранить состояние программы… уже лучше, но pickle в чистом виде мало пригоден. Нужно как минимум начинать с shelve (странно, что про него в статье ни слова).

                По сети передавать… лучше уж тогда сериализировать в xml или (что в последнее время более популярно) json. Для json, к примеру, есть библиотеки с API не на много сложнее pickle.

                Единственное, где я более менее часто встречал pickle — это хранение простых Python-структур в полях записи РСУБД. Но там в пару используют base64 и/или md5/sha1. Про это тоже ни полслова в статье…
                • –4
                  Хочешь — напиши лучше. Я описал базовое применение пикла.
                • 0
                  Да, иногда модули, написанные на С, работают быстрее их питоновских аналогов, но тут есть тонкости, в которые в этой статье я позволю себе не углубляться.


                  Иногда? O_o
                  • –1
                    Эх, не удалось ускользнуть от этой холиварной темы… :)

                    Показательно, что питоновские модули, написанные на С, можно пересчитать по пальцам.
                    • 0
                      Нет, я просто удивился. Неужто так быстро все выполняется?
                      • 0
                        Если ты про cPickle, то да. Действительно огромный прирост скорости. Ничего не попишешь, С — язык низкого уровня, а Питон — высокого. За удобство приходится платить.
                        • 0
                          Нет, я не об этом. Иногда Питон выполняется быстрее C?
                          • 0
                            Если Питоновская программа написана прямыми руками, а которая на С — кривыми, то да :)
                            Пример. Игра EVE-Online написана на чистом Питоне (клиент и сервер), и ничего.
                            • 0
                              точнее, stackless python
                              и клиент, например, не совсем на чистом. графический движок не на питоне, но предоставляет api для питона
                              • 0
                                Каюсь, забыл про стэклесс.
                                • 0
                                  Что-то мне казалось, что сервер Ив написан на яве, а в клиенте питон используется только в отдельных местах и для скриптования. Опровергнете?
                                  • 0
                                    Извините, я уже просветился. Вы правы.

                                    Черт, не зря я, наверное, питонщик, который любит только одну мморпг — именно эту (: все взяимосвязано, хе-хе.
                                    • +1
                                      У меня ж есть эти исходники, я просто так говорить не стану :)
                                      • 0
                                        Ух ты! А откуда, если не секрет?
                                        • 0
                                          Наверное, если я скажу, сразу же приедут люди и съедят мою собаку… ОК, Бухта.
                                          • 0
                                            Спасибо, посмотрю.
                                • 0
                                  дык она откомпилирована, небось, в таком случае разницы особой и нет, на каком языке написано
                                  • 0
                                    Но Питон-то они взяли не с потолка, не из-за прихоти.
                                    • 0
                                      может быть, они фанаты Пайтона?
                                      думаю, на нём разрабатывать быстрее, чем на С
                                      а против утечек памяти и т.п. они раз в сутки перезагружают сервер :)
                                      • 0
                                        нет. у них уникальность в том что любой объект в игре (например выпущеная ракета) — это отдельный микро-поток.

                                        почитайте про stackless. очень интересный подход.
                      • –1
                        OMFG, подумал я… Мой первый псто — и на глагнег!..
                        • 0
                          А на что похожи получившиеся «консервы»?
                          Их можно править в текстовом редакторе?
                          Или хотя бы просматривать?
                          • 0
                            ну если приловчиться, то можно просматривать. но совсем не рекомендую.
                            использовали cPickle в продакшене, для хранения данных готовых к отправке на сервер статистики. Данные были исключительно list и dict, были моменты когда этот pickle съезжал нафиг, вообщем отказались.
                            • +1
                              Если второй протокол, то ничего просмотреть особо не получится.
                            • 0
                              То, о чем вы написали называется «сериализацией». А «консервируют» продукты на зиму.
                            • 0
                              Действительно слабовато, описали два метода dump и load, а все тонкости проигнорировали.

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.