Распакуйте 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 ответ:
Теоретически,
cloudpickleне нужно устанавливать наloadмаринованный объект. Теоретически, то, чтоcloudpickleбудет делать, будет также включать все функции, необходимые для распаковки объекта внутри этого объекта. Впрочем, это в теории.В реестре методов (например, с помощью
copyreg) сериализатор должен зарегистрировать метод, который позволяет сериализатору создать новый объект требуемого типа и наполнить его сохраненным состоянием. Чтобы сериализатор не требовалось устанавливать на при загрузке сериализатор должен будет включить все необходимые методы десериализации в сам маринованный объект (это возможно, поскольку маринование рекурсивно).
cloudpickleпредполагается, чтоcloudpickleустановлен, и поэтому (чтобы сделать полученный маринованный объект меньше), не включает все необходимые методы. Это не похоже наnumpy, в качестве контрпримера, который методdumpsнаnumpy.arrayвключает методreconstructв рассоле (вы можете видеть это, посколькуnumpy.core.multiarray\n_reconstructпоявляется в любом маринованный огурецarray).