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