calling Python from C: I can't get this part.

Christian Tismer tismer at appliedbiometrics.com
Sun Dec 12 07:49:00 EST 1999


Very Frustrated wrote:
...
> typedef struct {
>         /* much stuff and */
>         FN_Ptr  EV_fun; /* a pointer to the function to be called */
>         /* more stuff */
> } *GA_Info_Ptr
> 
> Before the GA can be run, the EV_fun pointer has to be set by a call to a
> configuration function:
> 
> GA_Info_Ptr GA_config((*EV_fun)()) {
>         GA_Info_Ptr ga_info;
>         ga_info = CF_alloc(); /* this initializes a GA_Info_Ptr structure */
> 
>         /* the function pointer in the structure is then set to that given*/
>         /* in the call to GA_config()   */
> 
>      ga_info->EV_fun = EV_fun;
>         return ga_info;
> }
> 
> You would then call it like this in main() somewhere:
> 
> /* define your evaluation function */
> 
> int obj_fun(Chrom_Ptr chrom) {
>         /* do some stuff with chrom */
>         return;
> }
> 
> /* then call the configuration routine */
> GA_config(obj_fun);
> 
> Now, all I want to do is, instead of pointing to a C function that has to
> be compiled and included in the library, I want to have ga_info->EV_fun
> point to a Python function and have the Python function receive the
> (Chrom_Ptr chrom) argument.

You still have to provide a C function, but which just calls
a Python function.
The fastest way is probably to provide a PyObject pointer in your
C module and export a function to set this variable from Python.
In your module, you call it with PyEval_CallObject, for instance.

Untested code follows:

PyObject * myfunc = NULL;

PyObject *
SetPyFunction (self, args)
    PyObject * self, *args
{
    PyObject * func = NULL;
    if (!PyArg_ParseTuple("O", &func))
        return NULL;
    if (!PyCallable_Check(func)) {
        PyErr_SetString(PyExc_TypeError,
            "argument is not a callable object");
        return NULL;
    }
    Py_INCREF(func);
    myfunc = func;
}

You should export this function in your module's method table.

Now, just ignoring the structure of the Chrom_Ptr,
your calling stub looks something like this:

int obj_fun(Chrom_Ptr chrom) {
	PyObject * ret, *args;
        /* do some stuff with chrom */
        if (!myfunc)
            return -1; /* or whatever the error code is */
        /* analyse your Chrom_Ptr and build an argument
           tuple for the Python function. This can be more
           or less difficult.
           Then call the function: */
        ret = PyEval_CallObject(myfunc, args);
        /* do some error handling here, evaluate ret,
           don't forget to DECREF it, and so on... */
        return 0;
}

Now, what about the Chrom_Ptr thing? It depends on what is in it.
If it has a simple structure, maybe just a couple of floats or ints
with fixed size, the easiest would be to extract the values, build
PyObjects for them, stuff them into the args tuple, and done.
If that structure is much more complicated, you will need to
build a wrapper object for Python, which gives direct access to
the object via getattr and setattr methods.
Maybe this has been done for you already by SWIG?

Anyway good luck - chris

-- 
Christian Tismer             :^)   <mailto:tismer at appliedbiometrics.com>
Applied Biometrics GmbH      :     Have a break! Take a ride on Python's
Kaiserin-Augusta-Allee 101   :    *Starship* http://starship.python.net
10553 Berlin                 :     PGP key -> http://wwwkeys.pgp.net
PGP Fingerprint       E182 71C7 1A9D 66E9 9D15  D3CC D4D7 93E2 1FAE F6DF
     we're tired of banana software - shipped green, ripens at home




More information about the Python-list mailing list