使用 C 绑定导入代码的 Pickle 模块

Pickle module that imports code with C bindings

我有一个 class 我想用这个函数腌制:

def _pickle(self):
    """Pickle model instance.
    """
    fpath = f'{directory}/model.pickle'
    with open(fpath, 'wb') as f:
        pickle.dump(self, f, pickle.HIGHEST_PROTOCOL)

但是,在我的文件中我导入了一个库,PyPolyaGamma。它是一些 C 代码的 Python 包装器,可以从 Polya-gamma 分布中进行快速采样。当我尝试腌制 class 时,出现此错误:

Traceback (most recent call last):
  File "fit_model.py", line 262, in <module>
    model.fit(Y)
  File "/Users/gwg/projects/cdnlvm/kl_gplvmbase.py", line 97, in fit
    self._plot_and_print(t)
  File "/Users/gwg/projects/cdnlvm/kl_nbgplvm.py", line 456, in _plot_and_print
    self._pickle()
  File "/Users/gwg/projects/cdnlvm/kl_gplvmbase.py", line 352, in _pickle
    pickle.dump(self_, f, pickle.HIGHEST_PROTOCOL)
  File "stringsource", line 2, in pypolyagamma.pypolyagamma.PyPolyaGamma.__reduce_cython__
TypeError: no default __reduce__ due to non-trivial __cinit__

我的理解是Python不知道如何序列化PyPolyaGamma代码,可能是因为对C的依赖。正确的处理方法是什么?


如果您愿意安装 PyPolyaGamma,这是一个最小的完整示例:

# pickle_test.py

import pickle
from   pypolyagamma import PyPolyaGamma

class Model:
    def __init__(self):
        self.pg = PyPolyaGamma()

model = Model()
with open('test.pickle', 'wb+') as f:
    pickle.dump(model, f)

这将输出:

Traceback (most recent call last):
  File "pickle_test.py", line 15, in <module>
    pickle.dump(model, f)
  File "stringsource", line 2, in pypolyagamma.pypolyagamma.PyPolyaGamma.__reduce_cython__
TypeError: no default __reduce__ due to non-trivial __cinit__

不幸的是,您使用的 pypolyagamma 库目前似乎不支持 pickling/unpickling 这些对象,所以一句话:如果不修改库就无法腌制它们。

此外,由于它包装了 C++ class,因此 pickler/unpickler 并非微不足道;它需要知道 that wrapped class 中的什么状态对于对象在 unpickling 后处于相同状态是必要的。

作为包装器的替代方案,如果您不介意使用功能接口,那么我建议您改用 polyagamma。这解决了酸洗问题。它是一个用 C 编写的用于 Polya-Gamma 变量采样的 python 包。它很灵活,允许使用不同的采样方法,并且有一个类似于 Numpy 的 API。您可以通过 pip install -U polyagamma.

安装最新版本