Распакуйте cloudpickle без установки cloudpickle


Модуль

По умолчанию pickle из стандартной библиотеки Python не допускает сериализации функций с замыканиями, лямбдами или функциями в __main__ (см.здесь ).

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

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

Действительно, пример в документации делает в основном следующее:

Рассольник:

>>> import cloudpickle
>>> squared = lambda x: x ** 2
>>> pickled_lambda = cloudpickle.dump(squared, open('pickled_file', 'w'))

Unpickle:

>>> import pickle
>>> new_squared = pickle.load(open('pickled_file', 'rb'))
>>> new_squared(2)

Но запуск этого второго блока в среде, где cloudpickle не установлен, даже если он никогда не импортируется, дает ошибка:

"ImportError: No module named cloudpickle.cloudpickle"
Вероятно, наиболее легко воспроизводимым примером будет установка cloudpickle для Python2, запуск первого блока, а затем попытка загрузить в маринованный файл второй блок с помощью Python3 (где cloudpickle не был установлен).

Что здесь происходит? Почему cloudpickle должен быть установлен для запуска стандартной загрузки pickle, если он даже не вызывается?

1 2

1 ответ:

Теоретически, cloudpickle не нужно устанавливать на load маринованный объект. Теоретически, то, что cloudpickle будет делать, будет также включать все функции, необходимые для распаковки объекта внутри этого объекта. Впрочем, это в теории.

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

cloudpickle предполагается, что cloudpickle установлен, и поэтому (чтобы сделать полученный маринованный объект меньше), не включает все необходимые методы. Это не похоже на numpy, в качестве контрпримера, который метод dumps на numpy.array включает метод reconstruct в рассоле (вы можете видеть это, поскольку numpy.core.multiarray\n_reconstruct появляется в любом маринованный огурец array).