C API: array of floats/ints from python to C and back
Daniel Fetchinson
fetchinson at googlemail.com
Sat Dec 27 21:40:52 EST 2008
>> This is the function I have, the corresponding python function will
>> take two equal length lists of integers and the C function will
>> compute their sum and return the result as a python tuple.
>>
>>
>> static PyObject *func( PyObject * self, PyObject * args )
>> {
>> int j, N;
>> int * src1, * src2;
>> PyObject *list1, *list2;
>>
>> list1 = PyTuple_GetItem( args, 0 );
>> N = PyList_Size( list1 );
>> src1 = ( int * ) malloc( N * sizeof( int ) );
>> for( j = 0; j < N; j++ )
>> {
>> src1[j] = (int)PyInt_AsLong( PyList_GetItem( list1, j ) );
>> }
>>
>> list2 = PyTuple_GetItem( args, 1 );
>> N = PyList_Size( list2 );
>> src2 = ( int * ) malloc( N * sizeof( int ) );
>> for( j = 0; j < N; j++ )
>> {
>> src2[j] = (int)PyInt_AsLong( PyList_GetItem( list2, j ) );
>> }
>>
>> PyObject * tuple;
>> tuple = PyTuple_New( N );
>> for( j = 0; j < N; j++ )
>> {
>> PyTuple_SetItem( tuple, j, PyInt_FromLong( (long)( src1[j] +
>> src2[j] ) ) );
>> }
>>
>> free( src1 );
>> free( src2 );
>>
>> return tuple;
>> }
>
> As others already said, using a Numpy array or an array.array object would
> be more efficient (and even easier - the C code gets a pointer to an array
> of integers, as usual).
Thanks, I didn't know that an array.array can be passed to C code as a
C pointer to an array. So I'll use an array.array because this is
really convenient.
>> Do I have to free the memory occupied by the python objects list1 and
>> list2?
>
> No. Usually you don't do that for any Python object - just
> increment/decrement its reference count (using Py_INCREF/Py_DECREF).
Great, one headache less :)
>> Do I have to do any refcounting for list1, list2, tuple?
>
> In this case list1 and list2 come from PyTuple_GetItem; the docs say it
> returns a "borrowed reference" (that is, the function doesn't increment
> the refcount itself). So you don't have to decrement it yourself (and it
> isn't necesary to increment it in the first place, because the "args"
> tuple holds a reference, so the object can't disappear until the function
> exits, at least)
>
>> Any comment on the above code will be very appreciated! If I'm pushed
>> in the right direction I'm a fast learner but the beginning steps are
>> always hard :)
>
> You MUST check EVERY function call for errors!
Yes, I know :)
> And check the argument's type (how do you know it is a list?). Once you
> are sure the first parameter *is* a list, you may use the "macro" version
> of several functions, like PyList_GET_SIZE and PyList_GET_ITEM.
The macro versions are preferable because they are faster?
> You should check that both lists have the same length too.
> And you should check that elements are integers, or convertible to
> integers (in case of error, PyInt_AsLong returns -1 and PyErr_Occurred()
> is true)
> To fill the resulting tuple, use PyTuple_SET_ITEM instead. BTW, why return
> a tuple and not a list?
No particular reason, other than the fact that I won't need to modify
these lists/tuples from python so whenever something will not change,
I use a tuple because it's immutable. Or this is not a very good
practice? There is no difference between lists and tuples in terms of
speed I suppose (getitem, setitem, etc).
Thanks a lot,
Daniel
--
Psss, psss, put it down! - http://www.cafepress.com/putitdown
More information about the Python-list
mailing list