从c ++调用python对象的方法

时间:2016-02-17 20:24:44

标签: python c++ callback swig

我正在尝试实现以下功能:将python对象传递给c ++回调链(这在许多流行的c ++库中是典型的)。在c ++代码中,回调传递的对象具有级联/链中连续回调的必要信息。

这是我编写的一个小测试代码:我们将python对象传递给c例程(案例1)并调用它的方法。这没问题。但是,当我将python对象传递给c ++对象并尝试调用它时,"内部" c ++对象,我得到段错.. :(

这就是:

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&#34;导演&#34;但是,我想使用swig进行代码的一般包装,但是我的自定义包装用于此问题中描述的事情(即没有董事)。有没有办法实现这个目标?

b)任何其他建议,以达到我想在这里实现的目标,我们非常感谢..这是可能的还是纯粹的疯狂?

1 个答案:

答案 0 :(得分:0)

在构造函数中使用

po=this->po

解决&#34;问题&#34;。对不起垃圾邮件!我将把这件事留在这里作为一个例子......也许有人发现它很有用。