C-API: A beginner's problem

Georg Brandl g.brandl-nospam at gmx.net
Mon Mar 20 02:30:18 EST 2006


Fabian Steiner wrote:
> Georg Brandl wrote:
>> Fabian Steiner wrote:
>>> [...]
>>> 	for (i = 0; i <= seqlen; i++) {
>> 
>> That is one iteration too much. Use
>> 
>>         for (i = 0; i < seglen; i++)
>> 
>>> 		item = PySequence_Fast_GET_ITEM(seq, i);
>> 
>> Now item is a PyObject*. You'll have to convert it to an integer now:
>> 
>>                 it = PyInt_AsLong(item);
> 
> Why do you use PyInt_AsLong() here? As the documentation says it returns 
> a long type: long PyInt_AsLong(PyObject *io)
> On the other hand I can't find anything like PyInt_AsInt().

Python's int objects carry a long, so they can return you this long.
On most 32-bit platforms, int == long anyway, but for 64-bit you'd have
to declare list as long too.

>>                 if (it == -1 && PyErr_Occurred()) {
>>                     Py_DECREF(seq);
> 
> Why is this Py_DECREF() needed? What does it do exactly? When do I have 
> to call this function? Obviously, there is also Py_INCREF(). When do you 
> need this function?

This is for reference counting. Since you created seq with PySequence_Fast
you "own" a reference to it (it has reference count 1). Since nothing else
references that sequence, it has to be deallocated before the function exits.
You use Py_DECREF to decrease the reference count to 0, thus telling Python
that it's safe to free the memory associated with it.

Most API functions that return a PyObject increase its reference count by 1,
leaving you in charge to do something with this ("your") reference.

Other examples of how references can be juggled with:

item = PySequence_Fast_GET_ITEM(seq, i);

PySequence_Fast_GET_ITEM does return a PyObject, but it doesn't increase the
reference count, so you don't have to DECREF item anywhere. However, if you were
to store item in a structure of some sort, you'd have to INCREF it so that
Python doesn't destroy it while it's still referenced by your structure.

PyList_SetItem(newseq, i, PyInt_FromLong(list[i]));

PyInt_FromLong() returns a new PyObject with one reference, but PyList_SetItem
"steals" that reference from you (it stores the PyObject in a structure without
increasing its reference count). Therefore, you don't own a reference to the
integer object anymore and don't have to DECREF it.

newseq = PyList_New(seqlen);
(...)
return newseq;

Here, you own a reference to newseq, but you return the object, so you have to
keep it alive. Thus, no DECREF.

>> [...]
>> There's quite a bit you can overlook, especially stale references to PyObjects.
>> I'm not even sure the code compiles or runs correctly with my corrections ;)
> 
> Now, it compiles fine, without any warnings and using it in Python works 
> either :-) Now I have to try to understand what the different parts are 
> doing and why they are necessary.

Cheers,
Georg



More information about the Python-list mailing list