Pickle - это модуль Python для сериализации объектов, также известный как персистентность, маршаллинг или сплющивание.
Часто необходимо сохранить и восстановить содержимое объекта в файл. Одним из подходов к этой проблеме является написание пары функций, которые считывают и записывают данные из файла в специальном формате. Мощным альтернативным подходом является использование модуля маринования Python. Используя способность Python к интроспекции, модуль маринования рекурсивно преобразует почти произвольные объекты Python в поток байтов, которые могут быть записаны в файл.
Библиотека Boost Python поддерживает модуль маринования через интерфейс, как подробно описано в ссылке Python Library для маринования . Этот интерфейс включает в себя специальные методы _getinitargs__, _getstate__ и _setstate___, как описано ниже. Обратите внимание, что Boost.Python также полностью совместим с модулем Python cPickle.
На пользовательском уровне – рост. Интерфейс Python включает в себя три специальных метода:
__getinitargs__
Когда пример увеличения. Класс расширения Python маринован, пиклер тестирует, если экземпляр имеет метод _getinitargs__. Этот метод должен возвращать Python tuple (наиболее удобно использовать boost::python::tuple). Когда экземпляр восстанавливается разборщиком, содержимое этого кортежа используется в качестве аргументов для конструктора класса.
Если _getinitargs__ не определено, pickle.load вызовет конструктор (_init__) без аргументов; т.е. объект должен быть конструктивным по умолчанию.
__getstate__
Когда экземпляр Boost.Python класс расширения маринован, пиклер тестирует, если экземпляр имеет метод _getstate__. Этот метод должен возвращать объект Python, представляющий состояние экземпляра.
__setstate__
Когда экземпляр класса расширения Boost.Python восстанавливается антипиклером (pickle.load), он сначала конструируется с использованием результата _getinitargs___ в качестве аргументов (см. выше). Впоследствии тестировщик отсоединяется, если новый экземпляр имеет метод __setstate__. Если это так, то в качестве аргумента этот метод называется результатом _getstate__ (объект Python).
Три специальных способа, описанных выше, могут быть .def()'ed индивидуально пользователем. Однако Boost.Python обеспечивает простой в использовании высокоуровневый интерфейс через boost::python::pickle_suite Класс, который также обеспечивает согласованность: _getstate__ и _setstate__ должны быть определены как пары. Использование этого интерфейса показано на следующих примерах.
Класс C++ в этом примере может быть полностью восстановлен путем передачи соответствующего аргумента конструктору. Следовательно, достаточно определить способ огуречного интерфейса _getinitargs__. Это делается следующим образом: Определение функции огурца C++:
Класс C++ в этом примере содержит данные о членах, которые не могут быть восстановлены ни одним из конструкторов. Поэтому необходимо предоставить _getstate__/_setstate__ пару методов интерфейса пикселя:
Для простоты _dict__ не входит в результат _getstate__. Обычно это не рекомендуется, но допустимый подход, если предполагается, что объект _dict__ всегда будет пустым. Обратите внимание, что охранник, описанный ниже, улавливает случаи, когда это предположение нарушается.
Этот пример похож на pickle2.cpp. Однако объект _dict__ включен в результат _getstate__. Это требует немного больше кода, но неизбежно, если объект _dict__ не всегда пуст.
Протокол маринования, описанный выше, имеет важную ловушку, которую делает конечный пользователь Boost. Модуль расширения Python может не знать:
_getstate__ определено, и экземпляр _dict__ не пуст.
Автор класса расширений Boost.Python может предоставить метод _getstate___, не учитывая возможности того, что: * его класс используется в Python в качестве базового класса. Скорее всего, _dict__ экземпляров производного класса необходимо мариновать, чтобы правильно восстановить экземпляры. * пользователь добавляет элементы в экземпляр _dict__ напрямую. Опять же, _dict__ экземпляра должен быть замаринован.
Чтобы предупредить пользователя об этой неочевидной проблеме, предоставляется охранник. Если определен _getstate__ и экземпляр _dict__ не пуст, Boost.Python тестирует, если класс имеет атрибут _getstate_manages_dict__. Исключение делается, если этот атрибут не определен:
Чтобы решить эту проблему, сначала следует установить, что методы _getstate__ и _setstate__ правильно управляют экземплярами _dict__. Обратите внимание, что это можно сделать либо на уровне C++, либо на уровне Python. Наконец, охранник должен быть намеренно переопределен. Например, в C++ (от pickle3.cpp):
В модулях расширения Boost.Python, обеспечивающих полную поддержку огурцов для всех классов, будут значительные накладные расходы. В целом, полная поддержка маринования должна быть реализована только для классов расширения, которые в конечном итоге будут маринованы.
Избегайте использования _getstate__, если экземпляр также можно реконструировать с помощью _getinitargs__. Это автоматически позволяет избежать описанной выше ловушки.
Если требуется _getstate__, верните объект Python _dict__.
Пример pickle4.cpp демонстрирует альтернативную технику для реализации поддержки маринованных огурцов. Сначала мы снимаем Boost. Python через функцию class_::enable_pickling() определяет только основные атрибуты, необходимые для маринования:
Это позволяет использовать стандартный интерфейс Python, описанный в документации Python. Путем «впрыскивания» метода _getinitargs__ в определение класса обертывания мы делаем все экземпляры сборными:
См. также учебный раздел о введении дополнительных методов из Python.
Статья Pickle support раздела Boost.Python Reference Manual Chapter 8. Topics может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.