Google+ Tools
Make Google+ profile picture
Make Google plus banners for profile
Create and share your Google Plus profile banners.

Profile image for mrk studios pink chry on June 14, 2001

Lets say you have a function in C or C++ that takes a function callback as an argument. You want to call this function by passing a Python function as the callback. This recipe shows the basics by calling the standard C library function qsort, and passing a python function as the compare function.

Language
python
Tags

Implementing C function callbacks using Python


#include "python.h"

extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *));

static PyObject *py_compare_func = NULL;

static int
stub_compare_func(const PyObject **a, const PyObject **b)
{
    int retvalue = 0;

    // Build up the argument list... 
    PyObject *arglist = Py_BuildValue("(OO)", *a, *b);

    // ...for calling the Python compare function.
    PyObject *result = PyEval_CallObject(py_compare_func,arglist);

    if (result && PyInt_Check(result)) {
        retvalue = PyInt_AsLong(result);
    }

    Py_XDECREF(result);
    Py_DECREF(arglist);
    
    return retvalue;
}


static PyObject *pyqsort(PyObject *obj, PyObject *args)
{
    PyObject *pycompobj;
    PyObject *list;
    if (!PyArg_ParseTuple(args, "OO", &list, &pycompobj)) 
        return NULL;
    
    // make sure second argument is a function
    if (!PyCallable_Check(pycompobj)) {
        PyErr_SetString(PyExc_TypeError, "Need a callable object!");
    }
    else {
        // save the compare func. This obviously won't work for multi-threaded
        // programs.
        py_compare_func = pycompobj;
        if (PyList_Check(list)) {
            int size = PyList_Size(list);
            int i;
            
            // make an array of (PyObject *), because qsort does not know about
            // the PyList object
            PyObject **v = (PyObject **) malloc( sizeof(PyObject *) * size );
            for (i=0; i<size; ++i) {
                v[i] = PyList_GetItem(list, i);
                // increment the reference count, because setting the list items below
                // will decrement the ref count
                Py_INCREF(v[i]);
            }
            qsort(v, size, sizeof(PyObject*), stub_compare_func);
            for (i=0; i<size; ++i) {
                PyList_SetItem(list, i, v[i]);
                // need not do Py_DECREF - see above
            }
            free(v);
        }
    }
    Py_INCREF(Py_None);
    return Py_None;
}

static PyMethodDef qsortMethods[] = {
    { "qsort", pyqsort, METH_VARARGS },
    { NULL, NULL }
};

__declspec(dllexport) void initqsort(void) {
    PyObject *m;
    m = Py_InitModule("qsort", qsortMethods);
}


In Python
ActivePython 2.1, build 210 ActiveState)
based on Python 2.1 (#15, Apr 23 2001, 18:00:35) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import qsort
>>> a = [9, 3, 5, 4, 1]
>>> def revcmp(a, b): return cmp(b, a)
...
>>> qsort.qsort(a, revcmp)
>>> a
[9, 5, 4, 3, 1]
>>>

Comments

blog comments powered by Disqus