如何通过 Python/C API 将 Python 实例传递给 C++
How to pass Python instance to C++ via Python/C API
我正在用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脚本中创建一个GraphVisiter的实例,并为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 绑定生成器中添加了一个选项,用于使用 -external-runtime 选项生成用于外部访问 SWIG 运行时的头文件,因此我可以在 C++(下面的 INode*)中创建一个类并将其作为 python OnNode() 成员函数的参数传递给 Python,如下所示(为简洁起见,删除了错误检查):
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));
}
SWIG是否可能,但你可以用SIP做到这一点。
sip_vector_test.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_;
};
访客啜饮:
%Module pyvisit
%ModuleHeaderCode
#include "sip_visitor_test.h"
%End
class Node {
public:
explicit Node(int n);
int getN() const;
};
struct NodeVisitor {
virtual void OnNode(Node* n) = 0;
};
struct Graph {
public:
void addNode(int num);
void accept(NodeVisitor *nv);
};
从 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
我已经在我的主页上放了一个包含这个测试项目源代码的zip文件。
- 无法使用 SWIG 在 Python 中实例化C++类(获取属性错误)
- Python C API:如何检查对象是否是类型的实例
- 字节或整数地址预期,而不是str实例python 3
- swig c to python:抛出一个中止的实例后终止
- 如何使用 boost::p ython 创建和使用 Python 对象的实例
- 在python ctypes中截断了指向C++自定义类实例的指针地址
- 如何使用 SWIG 将 Python 类实例作为 C++ 函数的参数传递
- Python 可以运行脚本的多个实例,每个实例都包含自己的数据吗?
- 如何通过 Python/C API 将 Python 实例传递给 C++
- 用c++对象的全局实例扩展嵌入式python解释器
- boost python返回与makeconstructor相同的实例
- boost.python 解释器实例化
- 使用Boost::Python获取一个指向Python实例的c++指针
- 使用SWIG和Python/C API来包装一个函数,该函数采用C++类实例的Python列表
- 在BOOST_Python_MODULE宏之外将C++实例传递到Python中
- 实现具有自动增量实例属性的类的最python的方式是什么?
- 如何创建一个公共python函数,它可以接收c++结构体/实例或python对象作为参数
- 从Python中的另一个实例获取实例
- 向python嵌入式解释器公开c++类实例
- 如何从C++返回 Python 类型的实例