如何使用 pybind11 重新加载使用 C++ 源代码构建的 python 模块

she*_*per 6 c++ python pybind11

我正在使用 pybind11 文档中的第一步示例

#include <pybind11/pybind11.h>
int add(int i, int j)
{
    return i + j;
}
PYBIND11_MODULE(example, m)
{
    m.doc() = "pybind11 example plugin"; // optional module docstring
    m.def("add", &add, "A function which adds two numbers");
}
Run Code Online (Sandbox Code Playgroud)

一切正常,我可以在 python shell 中使用它:

import  example
example.add(2, 3) #returns 5
Run Code Online (Sandbox Code Playgroud)

现在我做了一个简单的更改,使用 float 而不是 int 作为 add() 的输入,一切都可以编译。我想重新加载模块示例,以便我可以测试新的基于浮点的 add()。但是,我无法找到重新加载示例模块的方法。importlib.reload不起作用, %autorelaod 2IPython不起作用。两种方法都经过测试可以与基于纯 python 的模块一起使用,但不能与基于 c++ 和 pybind11 的模块一起使用。

我在这里错过了什么吗?或者应该是这样的?

更新:似乎这是与如何重新加载 Python3 C 扩展模块相关的已知问题?

Python 的导入机制永远不会 dlclose() 共享库。加载后,库将一直保留到进程终止。

pybind11 模块和 ctypes 模块似乎在模块如何加载/导入方面具有相同的特征。另引用https://github.com/pybind/pybind11/issues/2511

Python 加载 C 扩展的方式不允许重新加载它们(与 Python 模块合同,Python 代码只能重新加载并且不引用动态加载的库)

我现在只是想知道是否有一种方法可以以更方便的方式包装它以重新加载模块。例如,为新的 python shell 生成一个子进程,该子进程复制所有与 C 扩展相关的变量/模块,并替换原始的。

Yux*_*xai 0

这似乎并不简单。由于可以通过手动 dlopen() 和 dlclose() 来管理标准共享库,因此您可以将 PYBIND11_MODULE 更改为预定义函数,例如

void __bind_module(void *bind_) {
  typedef void (*binder_t)(const char *, py::cpp_function);
  auto bind = (binder_t) bind_;
  bind("add", add);
}
Run Code Online (Sandbox Code Playgroud)

然后编写一个管理器模块来附加/分离这些库。比如你自己的 importlib 之类的东西。