Saturday 31 August 2013

How To Pass A C Array To Python Solution

While I commonly use C or C++ for processing signals there are not too many options available for displaying the results graphically so I have been looking at using Matplotlib for the display. The first problem I encountered is how to pass an array of floating point data from C to Python.
There are several options and a lot of forum discussions on the subject but I couldn't find a simple solution. So here is one that I developed earlier.
This example works with an Anaconda/Python v3.3 installation with the 64 bit Microsoft compiler.

See here for an introduction to  Anaconda/Python v3.3 installation and calling Python from the 64 bit Microsoft compiler : http://realgonegeek.blogspot.co.uk/2013/08/how-to-embed-python-pylab-into-64bit.html.

Here is the C code :

#include <Python.h>
#include <stdio.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include "C:\Anaconda\envs\py33\Lib\site-packages\numpy\core\include\numpy\arrayobject.h"

double Array [] = {1.2, 3.4, 5.6, 7.8};

int main (int argc, char *argv[])
{
    PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;
    npy_intp dims[1] = { 4 };
    PyObject *py_array;

    Py_Initialize ();
    pName = PyUnicode_FromString ("PrintArray");
    // PyUnicode_FromString error checking here

    pModule = PyImport_Import (pName);                  // Load the module object
    // PyImport_Import error checking here
    Py_DECREF(pName);

    pFunc = PyObject_GetAttrString (pModule, "PrintArray");        // pFunc is a new reference
    // PyObject_GetAttrString error checking here

    import_array ();                                    // Required for the C-API : http://docs.scipy.org/doc/numpy/reference/c-api.array.html#importing-the-api

    py_array = PyArray_SimpleNewFromData (1, dims, NPY_DOUBLE, Array);
    // PyArray_SimpleNewFromData error checking here

    pDict = PyModule_GetDict (pModule);                 // pDict is a borrowed reference

    pArgs = PyTuple_New (1);
    PyTuple_SetItem (pArgs, 0, py_array);

    pFunc = PyDict_GetItemString (pDict, "PrintArray"); // pFunc is also a borrowed reference

    if (PyCallable_Check (pFunc)) 
    {
        PyObject_CallObject (pFunc, pArgs);
    } else 
    {
        printf ("Function not callable !\n");
    }

    Py_DECREF (py_array);                               // Clean up
    Py_DECREF (pModule);
    Py_DECREF (pDict);
    Py_DECREF (pFunc);

    Py_Finalize ();                                     // Finish the Python Interpreter

    return 0;
}

Here is the python script to print the contents of the array :

def PrintArray (a):
    print ("Contents of a :")
    print (a)
    c = 0
    return c

If you have found this solution useful then please do hit the Google (+1) button so that others may be able to find it as well.
Numerix-DSP Libraries : http://www.numerix-dsp.com/eval/

6 comments:

  1. Thanks for the code

    the Py_DECREF(pDict); line gives

    Unhandled exception at 0x1E0ABA42 (python27.dll) in pythonEmbedded2.exe: 0xC0000005: Access violation reading location 0xFEEEFEF2.

    when I comment it out, it works fine.

    Any ideas as to why this is ?

    ReplyDelete
  2. Hi Asanka,
    No, I don't know why this occurs. I use Anaconda and it works fine.
    I'm glad it works for you when you remove the line.
    All the best,
    John

    ReplyDelete
  3. Hi John,

    THANKS FOR THE SOLUTION
    I have two doubts,
    1) How to get the array from python and use those array values in C
    2) Do we need to specify the size of the array in C. How to achieve the Dynamic memory allocation using your code.

    ReplyDelete
    Replies
    1. Hi Reji,
      Unfortunately, I did not need to get data back from Python to C so I have not tried it. If I get a chance I will work something out and upload it.
      Another option would be the SWIG API, I think this should do it.
      Yes, you could malloc Array in the C code although for the example I just created a fixed size array.
      John

      Delete
    2. It works great, thank you very much indeed! Have you found a way to get the array back from the python function?

      Delete
    3. Thank you for your comment. Unfortunately I did not need to get data back to C so I did not work that out.
      If you do find a solution then feel free to add a link to the thread.

      Good luck

      Delete