如何将Python实例传递给C++;通过Python/capi

如何将Python实例传递给C++;通过Python/capi,python,c++,python-2.7,swig,Python,C++,Python 2.7,Swig,我正在用Python(2.7)扩展我的库,方法是用SWIG 2.0包装接口,并有一个图形对象,我想在其中创建一个访问者。在C++中,界面看起来像这样: struct Visitor { virtual void OnStateBegin() = 0; virtual void OnNode(Node* n) = 0; virtual void OnStateEnd() = 0; }; 我想在Python中定义一个类,该类使

我正在用Python(2.7)扩展我的库,方法是用SWIG 2.0包装接口,并有一个图形对象,我想在其中创建一个访问者。在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脚本中创建一个GraveSuccor实例,并从C++调用给定实例的方法StATeEngEnter()、OnNoDeNe()和OnStAtEnEnter()。下面是我想用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中定义的函数,但实例让我难堪

我不知道用SWIG是否可以,但你可以用SWIG

sip_向量_测试。h:

class EXPORT Node {
public:
    explicit Node(int n) : n_(n) {};
    int getN() const { return n_; }
private:
    int n_;
};
struct EXPORT NodeVisitor {
    virtual void OnNode(Node* n) = 0;
};
struct EXPORT Graph {
public:
    void addNode(int num);
    void accept(NodeVisitor *nv);
private:
    std::vector< std::shared_ptr<Node> > nodes_;
};
从Python中使用它:

>>> import pyvisit
>>> g = pyvisit.Graph()
>>> g.addNode(3)
>>> g.addNode(5)
>>> class PyNodeVisitor(pyvisit.NodeVisitor):
>>>     def OnNode(self, node):
>>>         print(node.getN())
>>> pnv = PyNodeVisitor()
>>> g.accept(pnv)
3
5

我在我的主页上放了一个包含此测试项目源代码的文件。

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

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

    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个函数onStateBeagin()、OnNode()和OnStateEnd()。我添加到我的SpyPython绑定生成器中,生成一个用于访问SWIG运行时的头文件,用它,这样我就可以在C++中创建一个类(下面是iNoD*),并将它传递给Python作为Python OnNoDeNe()函数的参数(为简洁)删除错误:

VisitorCtrl OnNode(INode*node)
{
Node*Node_impl=新的NodeImpl(Node);
PyObject*pynode=SWIG_NewPointerObj(node_impl,SWIG_TypeQuery(“node*”),0);
PyObject*result=PyObject\u CallMethodObjArgs(\u inst,PyString\u FromString(“OnNode”),pynode,0);
长rivis=PyInt_AsLong(结果);
返回(静态_-cast(rivis));
}

mvis
只是python类的一个实例。它与您的
struct访问者
没有任何关系。在C/C++中,您只能作为
PyObject*
访问它。我知道这一点。我试图描述我在Python中定义访问者,那是C++对应的。你看到我以前的答案了吗?(你可以跳过关于嵌入的比特,但是从py物件转换到C++接口的一点点就做你想要的)Frimo——谢谢!你的东西真的很有用!谢谢你的回答!我没有使用SIP,我想看看这是否可以在不添加新类型的情况下完成。
    if(py_module)
    {
        PyObject* py_module_dict = PyModule_GetDict(py_module);
        PyObject* py_class = PyDict_GetItem(py_module_dict, class_name_obj);
        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);
            }
        }
    }
}
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));
}