序列化Boost Python函数

4 投票
2 回答
2091 浏览
提问于 2025-04-16 23:46

为了使用joblib.Parallel,我需要能够对一个boost::python函数进行序列化(也就是把它变成可以保存和传输的格式)。

TypeError: can't pickle builtin_function_or_method objects

根据我的理解,这个函数应该只通过它的完整名称来进行序列化。我不明白为什么这不行。有没有什么想法?

2 个回答

0

问题在于,joblib 正在尝试将一个传给 joblib.delayed 的函数转换成 pickle 格式,但它无法转换 Boost.Python.function 对象。为了解决这个问题,你可以使用一个不直接包含 Boost.Python.function 的可调用对象。你可以参考 这个链接 中提到的方法,使用一个包装器来实现。

我在使用 rdkit 时遇到了这个问题。下面是一个在 2022 年有效的解决方案示例。

import importlib

from joblib import Parallel, delayed


class Wrapper:
    def __init__(self, method_name, module_name):
        self.method_name = method_name
        self.module = importlib.import_module(module_name)

    @property
    def method(self):
        return getattr(self.module, self.method_name)

    def __call__(self, *args, **kwargs):
        return self.method(*args, **kwargs)


wrapped_mol_from_smiles = Wrapper("MolFromSmiles", "rdkit.Chem")
smiles = ["CCC", "CC"]
mols = Parallel(n_jobs=2, backend="loky")(
    delayed(wrapped_mol_from_smiles)(x) for x in smiles
)
print(mols)
2

如果你想在一个 joblib.Parallel 对象中使用你的 boost 方法,或许你可以给你的 boost 方法加一个包装器:

from joblib import Parallel, delayed
from boost import boost_function

class Wrapper(object):
    def __init__(self, method_name, module_name):
        self.method_name = method_name
        self.module_name = module_name

    def __call__(self, *args, **kwargs):
        method = __import__(self.module_name, globals(), locals(), [self.method_name,])
        return method(*args, **kwargs)

Parallel(n_jobs=1)(delayed(Wrapper("boost_module_name_with_dots", "boost_method_name")(i) for i in range(10))

撰写回答