2016-02-17 5 views
0

Я пытаюсь достичь следующего: передать объект python в цепочку обратного вызова C++ (что характерно для многих популярных библиотек C++). В коде C++ обратные вызовы передают объекты, которые имеют необходимую информацию для последовательных обратных вызовов в каскаде/цепочке.Вызов метода объекта python из C++

Вот небольшой тестовый код, который я написал: мы передаем объект python в подпрограмму c (случай 1) и вызываем его метод. Это работает нормально. Но когда я передать объект питона в объекнтую ++ и попытаться назвать его «внутри» 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++ отсасывает большое время, поэтому я мог пропустить что-то очевидное) ..?

Кроме того, некоторые бонусные вопросы:

а) Я знаком с глотком и Swig «директорами» .. однако, я хотел бы использовать глотнули для общей упаковки коды, но мой заказ упаковка для сортировки вещей, описанных в этом вопросе (т.е. без директоров). Есть ли способ достичь этого?

b) Любые другие предложения по достижению того, чего я пытаюсь достичь здесь, высоко ценятся .. это возможно или просто чистое безумие?

+0

К сожалению, передача функции обратного вызова из Python в C++ с помощью SWIG еще не очень хорошо поддерживается. Было бы достаточно количество кодов, которые вам нужно было бы написать вручную, и я считаю, что в нем есть несколько попыток. – AndyG

ответ

0

Использование в конструкторе

po=this->po 

решает "проблему". Извините за спам! Я оставлю здесь эту вещь в качестве примера. Может быть, кто-то сочтет это полезным.