how to pass C++ object to another C++ function via Python function

grbgooglefan ganeshborse at gmail.com
Thu May 1 23:26:38 EDT 2008


On Apr 22, 7:54 am, "Gabriel Genellina" <gagsl-... at yahoo.com.ar>
wrote:
>
> If you have a C function that receives a PyCObject, just include the  
> relevant headers (cobject.h) and you can retrieve the original pointer  
> using PyCObject_AsVoidPtr:
>
> void foo(PyObject *pyobj)
> {
>    TOriginalType *porig;
>    porig = (TOriginalType *)PyCObject_AsVoidPtr(pyobj);
>    // do something with porig
> }
> --
> Gabriel Genellina- Hide quoted text -
>
> - Show quoted text -

This works. But only once, means if I try to use this object second
time in Python function it causes crash.

What I am doing in my program is that I am putting STL map in a
structure & passing that structure as object to a Python function
alongwith other agurments of that Python function. This briefly as
below:

// In pyinterface.h file:---
typedef hash_map<char*,int> Elements;
typedef hash_map<char*,Elements*,StringHash,eqstr>
PerExchGroupsElementsTable;
typedef struct capsule {
        PerExchGroupsElementsTable* refgrps;
} *pcapsule;

// In pyinterface.cpp file:---
numvars = // value set depending on number of variables of that python
function
PyObject *pTuple = PyTuple_New(numvars);

// Set variables as below:
for(nCtr = 0; nCtr < numvars; nCtr++){
     slot = prul->pVarLst[nCtr].slot;
     ndtyp = ordvars[slot].dtype;
     switch(ndtyp){
       case(INT_T):
 
PyTuple_SetItem(pTuple,nCtr,PyInt_FromLong(ordvars[slot].nvalue));
           break;
       case(FLOAT_T):
 
PyTuple_SetItem(pTuple,nCtr,PyFloat_FromDouble(ordvars[slot].fvalue));
           break;
       case(STRING_T):
 
PyTuple_SetItem(pTuple,nCtr,PyString_FromString(ordvars[slot].cvalue));
           break;
       default:
           printf("\nUnknown data type [%d] for %s\n",ndtyp,prul-
>pVarLst[nCtr].var);
           bUnknownDataType = true;
           break;
     }
     if(bUnknownDataType){
        ret = -1;
        break;
     }
}

// Then set the C++ object as below:
if(ret == 0){
    capsule grpob;
    if(pGroups){
      grpob.refgrps = pGroups; // pGroups is pointer to
PerExchGroupsElementsTable map & is global.
      int ret = PyTuple_SetItem(pTuple,
(numvars-1),PyCObject_FromVoidPtr((void *)&grpob, NULL));
    }
    PyObject *pResult = PyObject_CallObject(pfunc,pTuple);
    if(PyErr_Occurred()){
       printf("error occured in PyObject_CallObject for %s\n",prul-
>pyobj.szPyRouteName);
       PyErr_Print();
    } else {
        printf("Python function passed, use its result for other
purposes as designed\n");
    }
    Py_XDECREF(pResult);
    Py_XDECREF(pTuple);
}

//---------- My Pythong module & functions in it -------------------
//PyObject* pfunc is a Python function which I compile dynamically &
add to my Python module as below:
// One of such dynamically compiled function is as below:
char pyfunction[]=\
"def TSE581(t22,t52,t1012,ob):
       if(co1(ob,t22,\"TSE_FUTURE_GRP\") and
like1(ob,t52,\"TSE_SECID_LST2\")):\n\
          print \"result is pass\"\n\
          return 1\n\
       else:\n\
          print \"result is fail\"\n\
          return 0\n";

// function parameter "ob" in this function definition is the one
which Im passing as CObject.

    PyObject *result = NULL;
    result =
PyRun_String(pyfunction,Py_file_input,_pPyDictionary,_pPyDictionary);
    if(PyErr_Occurred() || result == NULL){
        printf("Failed to compile function [%s]\n",func);
        PyErr_Print();
        return;
    }
    Py_XDECREF(result);
    result = NULL;
    PyObject *ptr = PyObject_GetAttrString(_pPyModule,fname);
    if(PyErr_Occurred() || *ptr == NULL){
        printf("PyObject_GetAttrString failed:%s",fname);
        return;
    }
    if(!PyCallable_Check(*ptr)){
       printf("%s not a callable Python code\n",fname);
       Py_XDECREF(*ptr);
       *ptr = NULL;
       return;
    }

// I've created dynamically loadble Python module & multiple functions
similar to above gets added dynamically to this module.
// Module has functions "co1" & "like1" in module's .cpp file. These
functions then use CObject - the struct capsule & map pointer in it.
static PyObject* merorderrouter_co1(PyObject* self, PyObject* args)
{
    printf("Contains function\n");
    int ret=0;
    char *arg1=NULL, *arg2=NULL;
    PyObject* voidcap=NULL;
    if(!PyArg_ParseTuple(args, "Oss", &voidcap,&arg1,&arg2)){
       printf("failed to get args\n");
       if(PyErr_Occurred())
         PyErr_Print();
       return(PyInt_FromLong(ret));
    }
    printf("key=%s, grpname=[%s]\n",arg1,arg2);
    if(voidcap && PyCObject_Check(voidcap))
       printf("valid Py-C-Object\n");
    else
       printf("NOT a valid Py-C-Object\n");
    pcapsule pobj = (pcapsule)PyCObject_AsVoidPtr(voidcap);
    if(pobj){
       PerExchGroupsElementsTable grpmap = *pobj->refgrps;
       if(grpmap.count(arg2)){
         PerExchGroupsElementsTable::iterator grpmi =
grpmap.find(arg2);
         Elements grpelems = *(Elements*)grpmi->second;
         Elements::iterator ei = grpelems.find(arg1);
         if(ei != grpelems.end()){
            printf("has elm.\n");
            ret=1;
         } else {
            printf("no elm.\n");
            ret=0;
         }
       }
    } else {
          printf("pcapsule object is null from PyCObject_AsVoidPtr
\n");
          if(PyErr_Occurred())
            PyErr_Print();
    }
    printf("------- co returning.....\n");
    return PyInt_FromLong(ret);
}
//=======================================================

What happens is that when Python function TSE581 gets called from my C
Program via PyObject_CallObject (as shown at top of this post), co1
function works fine & can access the map pointer properly.
But when next function like1 gets called, crash happens.

My queries are & things on which I need help are:
1) Is there anything wrong I am doing when I am passing the C-Object
from my C++ code->Python -> C++ code again?
2) Am I missing to increase or decrease the reference count somewhere.
3) I dont want map pointer to be ever freed because it is Process
level data structure & requried at every execution of these Python
functions. How do I avoid its cleanup when it gets passed to Python &
Python cleans up those objects.

If want to see my Python module & the CPP code using it, I can send
all my source code to you.
Please help.



More information about the Python-list mailing list