python - 如何通过 Python/C API 将 Python 实例传递给 C++

标签 python c++ python-2.7 swig

我通过使用 SWIG 2.0 包装接口(interface)来使用 Python (2.7) 扩展我的库,并且有一个图形对象,我想在其中创建一个访问者。在 C++ 中,界面如下所示:

    struct Visitor
    {
        virtual void OnStateBegin() = 0;
        virtual void OnNode(Node* n) = 0;
        virtual void OnStateEnd() = 0;
    };

我想在 Python 中定义一个类,它做同样的事情,全部在 python 中定义,这将允许定义访问者:

class GraphVisitor:
    def __init__(self, label):
        self._label = label
        print("__init__(self,{0})".format(self._label))
    def OnStateBegin(self):
        print("OnStateBegin()" + self._label)
    def OnNode(self, i_node):
        print("OnNode()" + self._label)
    def OnStateEnd(self):
        print("OnStateEnd()" + self._label)

我想做的是在 python 脚本中创建一个 GraphVisitor 实例,并从 C++ 中为给定实例调用方法 OnStateBegin()、OnNode() 和 OnStateEnd()。这是我想用 Python 做的事情:

#model is a SWIG wrapped class
mvis = GraphVisitor("This is a test")
model.Visit("mvis") # I'm not sure how to pass the instance 'mvis' to C++?

在我的由 Swig 封装的 C++ 中,我不确定如何获取实例“mvis”?我可以毫无问题地调用用 Python 定义的函数,但实例让我难住了!

最佳答案

为了解决这个问题,我根据模块名和类名从模块中检索了类(下面的代码假定模块尚未加载):

void Model::Visit(const char* mod_name, const char* class_name)
{
    PyErr_Clear();
    PyObject* mod_name_obj = PyString_FromString(mod_name);
    PyObject* class_name_obj = PyString_FromString(class_name);

    PyObject* py_module = PyImport_Import(mod_name_obj);
    PyObject* err_1 = PyErr_Occurred();
    if(err_1)
        PyErr_Print();

一旦我有了模块,我就从它的字典中查找类:

    if(py_module)
    {
        PyObject* py_module_dict = PyModule_GetDict(py_module);
        PyObject* py_class = PyDict_GetItem(py_module_dict, class_name_obj);

我通过在 C++ 中实例化 python 类来简化我的问题,然后创建我的访问者,最后访问它:

        if(py_class && PyClass_Check(py_class) && PyCallable_Check(py_class))
        {
            PyObject* inst = PyInstance_New(py_class, 0, 0);

            if(inst && PyInstance_Check(inst))
            {
                IModel::IVisitorPtr py_visitor = new PyModelVisitor(inst);

                _model->Visit(py_visitor);
            }
        }
    }
}

访问者有 3 个函数 OnStateBegin()、OnNode() 和 OnStateEnd()。我在我的 SWIG python 绑定(bind)生成器中添加了一个选项,用于生成头文件,以便使用 -external-runtime option 对 SWIG 运行时进行外部访问。 ,所以我可以在 C++ 中创建一个类(下面的 INode*)并将其作为参数传递给 Python OnNode() 成员函数,如下所示(为简洁起见删除了错误检查):

VisitorCtrl OnNode(INode* node)
{
    Node* node_impl = new NodeImpl(node);
    PyObject* pynode = SWIG_NewPointerObj(node_impl, SWIG_TypeQuery("Node *"), 0);
    PyObject* result = PyObject_CallMethodObjArgs(_inst, PyString_FromString("OnNode"), pynode, 0);

    long rivis = PyInt_AsLong(result);

    return(static_cast<VisitorCtrl>(rivis));
}

关于python - 如何通过 Python/C API 将 Python 实例传递给 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29928074/

相关文章:

python - 给定一个 N 边方阵,有没有办法在不使用循环或 if 条件的情况下找到单元格的环值?

c++ - 在编辑控件中显示无效输入的工具提示

python - 如何在不改变数据帧核心的情况下重新采样数据帧?

c++ - 在不构造容器的情况下对唯一元素进行迭代

c++ - 为什么 malloc() 基于链表?

python - 从列表中查找有序子序列(不一定是连续的)

python - 在 python 日志记录配置文件中使用程序变量

python-2.7 - Python 2.7 xlsxwriter 未使用 valign 正确格式化数据

Python:带有关键字参数的递归函数的奇怪行为

python - 评论帖子时如何通过postid获取帖子的用户id?