Python | An extension function that works with arrays



The code must use a buffer protocol to receive and process arrays in a portable form. The code below is a C extension function that takes array data and calls the avg (double * buf, int len) function from this article — 

/ * Call double mean (double *, int) * /

static PyObject * py_avg (PyObject * self, PyObject * args)

{

PyObject * bufobj; 

Py_buffer view; 

double result; 

/ * Get passed Python object * /

if (! PyArg_ParseTuple (args, "O" , & amp; bufobj))

{

return NULL; 

}

 

  / * An attempt to extract information about the buffer from it * /

 

if (PyObject_GetBuffer (bufobj, & amp; view,

PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT) == -1)

  {

return NULL; 

}

 

  if ( view.ndim! = 1)

{

PyErr_SetString (PyExc_TypeError, "Expected a 1-dimensional array" ); 

PyBuffer_Release (& amp; view); 

return NULL; 

}

 

  / * Check the type of elements in the array * /

if ( strcmp (view.format, " d " ) ! = 0)

{

PyErr_SetString (PyExc_TypeError, "Expected an array of doubles" ); 

PyBuffer_Release (& amp; view); 

return NULL; 

}

 

  / * Pass raw buffer and size to C function * /

result = avg (view.buf, view.shape [0]); 

 

/ * Indicate that we are done with the buffer * /

  PyBuffer_Release (& amp; view); 

return Py_BuildValue ( "d" , result); 

}

Code # 2: How This Extension Function Works

import array

 

print ( "Average:" , avg (array.array ( `d` , [ 1 , 2 , 3 ])))

 

import numpy

print ( " Average numpy arra y: " , avg (numpy.array ([ 1.0 , 2.0 , 3.0 ])))

print ( " Average list: " , avg ([ 1 , 2 , 3 ]))

Output:

 Average: 2.0 Average numpy array: 2.0 
 Average list: Traceback (most recent call last): File "", line 1, in TypeError: `list` does not support the buffer interface  

  • PyBuffer_GetBuffer() is the key to the code in the article.
  • It tries to get information about memory representation in a given arbitrariness on a Python object.
  • It just throws an exception and returns -1 if no information is available (as is the case with regular Python objects).
  • Special flags passed to PyBuffer_GetBuffer () give additional hints about the type of memory buffer requested.
  • Because PyBUF_ANY_CONTIGUOUS indicates that a contiguous region is required memory.