仅在对象实例的生命周期内保持 Python 解释器处于活动状态
Posted
技术标签:
【中文标题】仅在对象实例的生命周期内保持 Python 解释器处于活动状态【英文标题】:Keeping Python Interpreter Alive Only During the Life of an Object Instance 【发布时间】:2020-02-06 17:53:55 【问题描述】:我已经定义了一个使用python解释器的类如下:
class pythonInt
public:
pythonInt(const char* fname)
py::initialize_interpreter();
m_Module = py::module::import(fname);
~pythonInt()
py::finalize_interpreter();
py::module m_Module;
// ... other class members and functions that uses m_Module
;
int main()
pythonInt *p1 = new pythonInt("pybind_test1");
delete(p1);
pythonInt *p2 = new pythonInt("pybind_test1");
delete(p2);
return 0;
一旦类实例被破坏,当它到达删除实例_Py_Dealloc(op)
时,我会收到Access violation reading location
错误。如何完成解释器,以便成功删除之前创建的类实例p1
并安全地创建一个新的类实例p2
?
【问题讨论】:
【参考方案1】:崩溃是b/c数据成员py::module m_Module;
在pythonInt
的构造函数/析构函数运行之前创建并在运行之后销毁,因此在初始化之前和解释器完成之后。
pybind11 为您寻求的目的提供scoped_interpreter
,C++ 保证访问块中所有数据成员的构造/销毁顺序。因此,假设您将所有(Python)数据保存在一起并且pythonInt
没有基类(带有 Python 数据成员),这将是一个选项:
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>
namespace py = pybind11;
class pythonInt
public:
pythonInt(const char* fname)
m_Module = py::module::import(fname);
~pythonInt()
py::scoped_interpreter m_guard;
py::module m_Module;
// ... other class members and functions that uses m_Module
;
int main()
pythonInt *p1 = new pythonInt("pybind_test1");
delete(p1);
pythonInt *p2 = new pythonInt("pybind_test2");
delete(p2);
return 0;
与您的示例相比,它添加了#include <pybind11/embed.h>
和py::scoped_interpreter m_guard;
(再次强调顺序至关重要);它删除了解释器的初始化/终结。
【讨论】:
谢谢维姆。代码成功通过delete(p1)
,这很棒。但是,它停在pythonInt *p2 = new pythonInt("pybind_test2");
并给出error alreary set
。
py::error_already_set
异常的 what()
打印出实际 Python 异常的 str()
。那么,它完整地说明了什么?如果没有,请在语句周围使用try catch(...)
并通过PyErr_Print()
打印错误。 pybind_test1
或 pybind_test2
模块中很可能存在 Python 错误。
我实际上将同一个文件传递给p1
和p2
,它只在p2
上引发异常。我得到的错误是:Unhandled exception at 0x00007FFE27D0A839 in mypython_test.exe: Microsoft C++ exception: pybind11::error_already_set at memory location 0x0000009827F5F9B8
。返回的对象PyObject *obj = PyImport_ImportModule(name);
是NULL
。
如果PyImport_ImportModule
返回NULL
,表示找不到模块。为了简化测试,请使用肯定存在的模块,例如。 sys
.
在pybind_test1.py
或(在使用的模块中)看起来像引用计数问题。错误是 b/c 此谓词 (Py_REFCNT(type) != 0)
对于 PyStructSequence
类型失败。请注意,Python 解释器从不卸载共享库,即使此类库表示的扩展模块已完全删除,因此任何数据对象都会保留,并且显然引用计数没有正确减少。在pybind_test1.py
上进行一些增量调试,删除部分以查找有问题的代码,将允许精确定位有问题的代码(但您可能对此无能为力)。以上是关于仅在对象实例的生命周期内保持 Python 解释器处于活动状态的主要内容,如果未能解决你的问题,请参考以下文章
如何创建仅在 JVM 生命周期内存在的 HSQLDB 数据库?