简体   繁体   中英

Calling python object's method from c++

I am trying to achieve the following: passing a python object to a c++ callback chain (which are typical in many popular c++ libraries). In the c++ code, callbacks pass on objects that have necessary information for consecutive callbacks in the cascade/chain.

Here is a small test code I wrote: we pass a python object to ac routine (case 1) and call it's method. That works ok. But when I pass the python object to a c++ object and try to call it "inside" the c++ object, I get segfault.. :(

Here it goes:

c++ module ("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)

This question seems relevant:

Calling python method from C++ (or C) callback

.. however the answer did not help me.

What am I missing/misunderstanding here (my c++ sucks big time, so I might have missed something obvious) .. ?

Also, some bonus questions:

a) I am familiar with swig and swig "directors".. however, I would like to use swig for general wrapping of the code, but my custom wrapping for the sort of things described in this question (ie without directors). Is there any way to achieve this?

b) Any other suggestions to achieve what I am trying to achieve here, are highly appreciated.. is this possible or just pure insanity?

Using in the constructor

po=this->po

solves the "issue". Sorry for the spam! I will leave here this thing as an example.. maybe someone finds it useful.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM