returning a python array from a C extension

Scott Gilbert xscottgjunk at yahoo.com
Mon May 27 22:24:27 EDT 2002


Maxwell Todd Sayles <sayles at cpsc.ucalgary.ca> wrote: 
> in python i can write:
> 
> from array import *
> a = array ('B', 'some test data')
> 
> and a refers to an array object.
> 
> now i have a C extension for python that returns a PyString, and within
> python i can convert it to an array
> 
> e.g.:
> 
> from array import *
> from MyCExtension import *
> a = array ('B', cfunction())
> 
> but this method requires an extra copy and construction from the string
> to the array.
> 
> is there a way i can have cfunction return a python array?  i tried
> looking through the include files with the Python/C API and couldn't
> find anything.  any help would be appreciated.
> 

Yes, but since arraymodule.c doesn't have a C level API, you have to
use C to do what you would do from Python.  I haven't compiled this,
and I'm being a little sloppy so you should read the docs, but it
would be something like:

  /* declarations */
  PyObject* globals;
  PyObject* ignore;
  PyObject* array;
  char* pointer;
  int length;

  /* setup */
  globals = PyDict_New();

  /* import array */
  ignore = PyRun_String(
      "import array",
      Py_file_input, globals, globals
  );
  Py_XDECREF(ignore);

  /* create a 1234 byte array object */
  array = PyRun_String(
      "array.array('B', 'X')*1234", 
      Py_eval_input, globals, globals
  );

  /* use the PyBufferProcs to get a pointer to your n bytes */
  PyObject_AsWriteBuffer(array, &pointer, &length);

  /* build your data in your new pointer (no copy required) */
  memset(pointer, 'Z', length);

  /* cleanup */
  Py_XDECREF(globals);

  /* return put it some where... */
  return array;


Also note that if your array is really big, it would be faster to
multiply in parts:

  /* create a 16 meg array */
  array = PyRun_String(
      "array.array('B', 'X')*1024*1024*16",
      Py_eval_input, globals, globals
  );

Finally, it would probably be better to get the globals dict from a
real module - using the PyModule_GetDict(...) API instead of
PyDict_New().  I think the above will work today, but I suspect
someday that might not be the case...


Cheers,
    -Scott



More information about the Python-list mailing list