473,325 Members | 2,442 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,325 software developers and data experts.

returning a list of tuples -- C API


I am writing a python extension module and have a reference counting
question

My function looks like

static PyObject *
pokereval_seven_cards(PyObject *self, PyObject *args)
{

int i;

PyObject * tup;
PyObject * list;

// ... snip ...

list = PyList_New(HandType_LAST+1);
for (i = HandType_FIRST; i <= HandType_LAST; i++) {
tup = Py_BuildValue("(s,h)", handTypeNamesPadded[i], totals[i]);
PyList_SetItem(list, i, tup);
totals[i] = 0;
}
Py_INCREF(list);
return list;

}

Should I be incrementing the ref of tup each time I call
Py_BuildValue? Is it correct to increment the ref of list before I
return it? Does it make a difference vis-a-vis ref counting if I
create the tuple with Py_BuildValue or PyTuple_New?

Thanks,
John Hunter

Jul 18 '05 #1
1 2479
"John Hunter" <jd******@ace.bsd.uchicago.edu> wrote in message
news:ma**************************************@pyth on.org...
"""
My function looks like

static PyObject *
pokereval_seven_cards(PyObject *self, PyObject *args)
{

int i;

PyObject * tup;
PyObject * list;

// ... snip ...

list = PyList_New(HandType_LAST+1);
for (i = HandType_FIRST; i <= HandType_LAST; i++) {
tup = Py_BuildValue("(s,h)", handTypeNamesPadded[i], totals[i]);
PyList_SetItem(list, i, tup);
totals[i] = 0;
}
Py_INCREF(list);
return list;

}
"""
Should I be incrementing the ref of tup each time I call
Py_BuildValue?
No. Py_BuildValue is declared by the docs to return a new reference. In
your case, the 'tup = Py_BuildValue(...)' call creates a new object and
gives you a new reference to it. PyList_SetItem is declared by the docs (in
7.3.5 List Objects and 1.2.1.1 Reference Count Details) to "steal" a
reference to its third argument, so your 'PyList_SetItem(list, i, tup);'
call transfers ownership of the tuple reference (which you acquired in the
previous statement) to the list object. So you're first gaining ownership
of a reference to the tuple, then losing that ownership to the list, which
will decrement the reference count of the tuple when the list itself is
released.
Is it correct to increment the ref of list before I return it?
No. You created list within this C function, so you already own the only
reference to it; that ownership must be either discarded or transferred
before you exit the function. In your case, you should transfer to the
caller ownership of the only reference to list (i.e., get rid of the
'Py_INCREF(list); return list;' in favor of only 'return list;').
Does it make a difference vis-a-vis ref counting if I
create the tuple with Py_BuildValue or PyTuple_New?


No. The docs declare that both return a new reference.
P.S. For optimal robustness, you ought to check the return value of
PyList_New and Py_BuildValue to make sure there was adequate memory to
allocate the new object. E.g.,
list = PyList_New(HandType_LAST+1);
if (list == NULL) {
return PyErr_NoMemory();
}

In the case of the Py_BuildValue call, you'd need to discard the reference
to list before raising a MemoryError, e.g.:
tup = Py_BuildValue("(s,h)", handTypeNamesPadded[i], totals[i]);
if (tup == NULL) {
Py_DECREF(list);
return PyErr_NoMemory();
}

In large C functions, it becomes error-prone to discard all necessary
references in each place an exception might be raised. The typical solution
(AFAIK) is to set to NULL at the beginning of the function all PyObject
pointers that might need to be released if an error arises, then have a
labelled error handler that discards those references, e.g. (warning:
untested code),

--------------
static PyObject *
pokereval_seven_cards(PyObject *self, PyObject *args)
{
int i;

PyObject *tup = NULL;
PyObject *list = NULL;

// ... snip ...

list = PyList_New(HandType_LAST+1);
if (list == NULL) {
PyErr_NoMemory();
goto err_handler;
}
for (i = HandType_FIRST; i <= HandType_LAST; i++) {
tup = Py_BuildValue("(s,h)", handTypeNamesPadded[i], totals[i]);
if (tup == NULL) {
PyErr_NoMemory();
goto err_handler;
}
if (PyList_SetItem(list, i, tup) == -1) {
goto err_handler;
}
totals[i] = 0;
}
return list;

err_handler:
assert(PyErr_Occurred()); /* An exception must already be set. */

if (tup != NULL && !PySequence_Contains(list, tup)) {
Py_DECREF(tup);
}
Py_XDECREF(list);

return NULL;
}
--------------

As you can see, things get ugly fast. One of objectives of tools such as
Pyrex is to free the programmer from micromanaging reference counts.
Jul 18 '05 #2

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Thorsten Kampe | last post by:
I found out that I am rarely using tuples and almost always lists because of the more flexible usability of lists (methods, etc.) To my knowledge, the only fundamental difference between tuples...
24
by: Mandus | last post by:
Hi there, inspired by a recent thread where the end of reduce/map/lambda in Python was discussed, I looked over some of my maps, and tried to convert them to list-comprehensions. This one I...
14
by: Richard | last post by:
I have a large list of two element tuples. I want two separate lists: One list with the first element of every tuple, and the second list with the second element of every tuple. Each tuple...
18
by: a | last post by:
can someone tell me how to use them thanks
11
by: Noah | last post by:
I have a list of tuples I want to reverse the order of the elements inside the tuples. I know I could do this long-form: q = y = for i in y: t=list(t)
10
by: rshepard | last post by:
While working with lists of tuples is probably very common, none of my five Python books or a Google search tell me how to refer to specific items in each tuple. I find references to sorting a list...
7
by: Shafik | last post by:
Hello folks, I am an experienced programmer, but very new to python (2 days). I wanted to ask: what exactly is the difference between a tuple and a list? I'm sure there are some, but I can't...
3
by: Jonathan Lukens | last post by:
I am in the last phase of building a Django app based on something I wrote in Java a while back. Right now I am stuck on how to return the matches of a regular expression as a list *at all*, and...
5
by: Cromulent | last post by:
Okay I'm having a few issues with this and I can't seem to get it sorted out (most likely due to my inexperience with Python). Here is my Python code: def fileInput(): data = s =...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.