使用pybind11嵌入Python解释器时如何清除模块缓存?
解决pybind11嵌入Python时动态切换同名模块的问题
问题根源
Python解释器会将已加载的模块缓存到sys.modules字典中,即使修改sys.path并调用importlib.invalidate_caches(),再次import同名模块时仍会直接读取该缓存,而非重新从文件系统加载。invalidate_caches()仅用于刷新Python对模块文件的查找缓存,不会清除已加载的模块实例。
解决方案
要实现动态切换同名模块,需在切换路径时同时清除sys.modules中对应模块的缓存,确保下次import时重新加载新路径下的模块。
修改后的代码示例
#include <pybind11/pybind11.h> #include <pybind11/embed.h> namespace py = pybind11; void addModulePath(const std::string &module) { auto sys = py::module::import("sys"); auto importlib = py::module::import("importlib"); auto path = sys.attr("path"); path.attr("append")(module); importlib.attr("invalidate_caches")(); } void deleteModulePath(std::string& module) { auto sys = py::module::import("sys"); auto importlib = py::module::import("importlib"); auto path = sys.attr("path"); path.attr("remove")(module); importlib.attr("invalidate_caches")(); } void clearModuleCache(const std::string& moduleName) { auto sys = py::module::import("sys"); auto modules = sys.attr("modules"); // 检查模块是否在缓存中,存在则移除 if (py::hasattr(modules, moduleName)) { modules.attr("pop")(moduleName); } } PYBIND11_EMBEDDED_MODULE(changeModule, m) { m.def("add_module", &addModulePath, "add module path"); m.def("delete_module", &deleteModulePath, "delete module path"); m.def("clear_module_cache", &clearModuleCache, "clear specified module from sys.modules"); } int main() { constexpr auto test1Path = "/tmp/test1"; constexpr auto test2Path = "/tmp/test2"; py::scoped_interpreter guard{}; py::module_ module = py::module_::import("changeModule"); // 加载第一个路径的test模块 module.attr("add_module")(test1Path); auto test = py::module_::import("test"); test.attr("test")(); // 清理旧路径和模块缓存 module.attr("delete_module")(test1Path); module.attr("clear_module_cache")("test"); // 加载第二个路径的test模块 module.attr("add_module")(test2Path); test = py::module_::import("test"); test.attr("test")(); return 0; }
配套Python模块示例
/tmp/test1/test.py:
def test(): print("Running test from /tmp/test1")
/tmp/test2/test.py:
def test(): print("Running test from /tmp/test2")
关键修改说明
- 新增
clearModuleCache函数:负责检查并移除sys.modules中指定模块的缓存条目 - 在删除旧模块路径后、添加新路径前调用该函数,确保已加载的
test模块被完全清除 - 再次执行
import test时,Python会重新遍历当前sys.path,加载新路径下的模块文件
内容的提问来源于stack exchange,提问作者Christoph Meyer
相关产品推荐
相关产品推荐

