【发布时间】:2016-02-17 20:24:43
【问题描述】:
我正在尝试实现以下目标:将 python 对象传递给 c++ 回调链(这在许多流行的 c++ 库中很常见)。在 c++ 代码中,回调传递的对象具有级联/链中连续回调所必需的信息。
这是我编写的一个小测试代码:我们将一个 python 对象传递给一个 c 例程(案例 1)并调用它的方法。这行得通。但是当我将 python 对象传递给 c++ 对象并尝试在 c++ 对象“内部”调用它时,我得到了 segfault.. :(
这里是:
c++ 模块(“some.cpp”):
#include <stdint.h>
#include <iostream>
#include <Python.h>
/* objective:
* create c++ objects / routines that accept python objects
* then call methods of the python objects inside c++
*
* python objects (including its variables and methods) could be passed along, for example in c++ callback chains ..
* .. and in the end we could call a python callback
*
* Compile and test as follows:
* python setup.py build_ext
* [copy/link some.so where test.py is]
* python test.py
*
*/
class testclass {
public:
testclass(int* i, PyObject* po) {
std::cerr << "testclass constructor! \n";
i=i; po=po;
}
~testclass() {}
void runpo() {
PyObject* name;
const char* mname="testmethod";
name=PyString_FromString(mname);
std::cerr << "about to run the python method .. \n";
PyObject_CallMethodObjArgs(po, name, NULL);
std::cerr << ".. you did it - i will buy you a beer!\n";
}
public:
int* i;
PyObject* po;
};
/* Docstrings */
static char module_docstring[] = "hand-made python module";
/* Available functions */
static PyObject* regi_wrapper(PyObject * self, PyObject * args);
void regi(int* i, PyObject* po);
/* Module specification */
static PyMethodDef module_methods[] = {
{"regi_wrapper",regi_wrapper, METH_VARARGS, "lets see if we can wrap this sucker"},
{NULL, NULL, 0, NULL}
};
/* Initialize the module */
PyMODINIT_FUNC initsome(void)
{
PyObject *m = Py_InitModule3("some", module_methods, module_docstring);
if (m == NULL)
return;
// import_array(); // numpy not required here ..
}
static PyObject* regi_wrapper(PyObject * self, PyObject * args)
{
int* input_i; // whatever input variable
PyObject* input_po; // python object
PyObject* ret; // return variable
// parse arguments
if (!PyArg_ParseTuple(args, "iO", &input_i, &input_po)) {
return NULL;
}
// https://stackoverflow.com/questions/16606872/calling-python-method-from-c-or-c-callback
// Py_INCREF(input_po); // need this, right? .. makes no difference
/* // seems not to make any difference ..
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
*/
regi(input_i, input_po);
// PyGILState_Release(gstate); // .. makes no difference
// Py_DECREF(input_po); // .. makes no difference
Py_RETURN_TRUE;
}
void regi(int* i, PyObject* po) {
// search variable and methods from PyObject "po" and call its methods?
PyObject* name;
const char* mname="testmethod";
testclass* testobj;
testobj=new testclass(i,po);
/* [insert // in front of this line to test case 1]
// ***** this one works! *********
name=PyString_FromString(mname);
PyObject_CallMethodObjArgs(po, name, NULL);
*/ // [insert // in front of this line to test case 1]
// *** I WOULD LIKE THIS TO WORK *** but it gives segfault.. :(
testobj->runpo(); // [uncomment to test case 2]
}
setup.py:
from distutils.core import setup, Extension
# the c++ extension module
extension_mod = Extension("some", ["some.cpp"])
setup(name = "some", ext_modules=[extension_mod])
test.py:
import some
class sentinel:
def __init__(self):
pass
def testmethod(self):
print "hello from sentinel.testmethod"
pass
se=sentinel()
some.regi_wrapper(1,se)
这个问题似乎很相关:
Calling python method from C++ (or C) callback
.. 但是答案对我没有帮助。
我在这里遗漏/误解了什么(我的 c++ 很糟糕,所以我可能遗漏了一些明显的东西)..?
另外,一些额外的问题:
a)我熟悉 swig 和 swig “导演”.. 但是,我想使用 swig 对代码进行一般包装,但我对这个问题中描述的那种事情进行了自定义包装(即没有导演) .有什么方法可以实现吗?
b) 任何其他建议来实现我在这里想要实现的目标,非常感谢.. 这是可能的还是纯粹的精神错乱?
【问题讨论】:
-
不幸的是,通过 SWIG 将回调函数从 Python 传递到 C++ 还没有得到很好的支持。您需要手写大量的 swig 代码,我相信有一些尝试。