Python lists ans sequence protocol from C API

M

Matjaz

Dear all,

I have run into a problem using python lists and sequence protocol.
The first code snippet uses explicit list operations and works fine.


PyObject *argseq, *ov;
int i, v, len;

len = 2;
argseq = PyList_New(len);
for (i=0; i<len; i++) {
ov = PyInt_FromLong(i);
printf("Index %d. Success %d.\n", i, PyList_SetItem(argseq, i, ov));
}
for (i=0; i<len; i++) {
ov = PyList_GetItem(argseq,i);
v = PyInt_AsLong(ov);
printf("Index %d. Read %d.\n", i, v);
}

Output:

Index 0. Success 0.
Index 1. Success 0.
Index 0. Read 0.
Index 1. Read 1.

Argseq results in a python list [0, 1], as it should.
However, if I change the above code to use sequence protocol
for GetItem and SetItem (see below), the program fails when calling
PySequence_SetItem with the following error message:
"Unhandled exception at 0x1e04ed1a in python.exe:
0xC0000005: Access violation reading location 0x00000000."
Could it be that basic lists do not support sequence protocol?
Or am I missing something? I'm using Python 2.3.4 on Windows XP.

PyObject *argseq, *ov;
int i, v, len;

len = 2;
argseq = PyList_New(len);
for (i=0; i<len; i++) {
ov = PyInt_FromLong(i);
printf("Index %d. Success %d.\n", i, PySequence_SetItem(argseq, i, ov));
}
for (i=0; i<len; i++) {
ov = PySequence_GetItem(argseq,i);
v = PyInt_AsLong(ov);
printf("Index %d. Read %d.\n", i, v);
}

Why would I wish to use sequence with basic lists protocol? Because my code should
also deal with other sequence types, possibly subclassed from python lists.

Thanks,

Matjaz.
 
A

Alex Martelli

Matjaz said:
PySequence_SetItem with the following error message:
"Unhandled exception at 0x1e04ed1a in python.exe:
0xC0000005: Access violation reading location 0x00000000."
Could it be that basic lists do not support sequence protocol?

Once they're valid Python list objects, they do...
Or am I missing something? I'm using Python 2.3.4 on Windows XP.

You're missing the fact that you're never building a valid Python list
object in your code. The slots, as PyObject*, are 'random', probably
null pointers. That's why you're supposed to use PyList_SET_ITEM
specifically to initialize these 'slots' WITHOUT trying to decref the
previously held item... there IS no 'previously held item'...!
PyObject *argseq, *ov;
int i, v, len;

len = 2;
argseq = PyList_New(len);

This does NOT initialize the slots of list argseq, as above explained.
for (i=0; i<len; i++) {
ov = PyInt_FromLong(i);
printf("Index %d. Success %d.\n", i, PySequence_SetItem(argseq, i, ov));
}

But this does try to decref that null pointer (or whatever), so, BOOM.
Why would I wish to use sequence with basic lists protocol? Because my
code should also deal with other sequence types, possibly subclassed from
python lists.

Nevertheless they'll need to be properly built, inizialized, first.

Add initialization, such as an immediate:
for (i=0; i<len; i++) {
PyList_SET_ITEM(argseq, i, Py_BuildValue(""));
}
just after your
argseq = PyList_New(len);
and you should be fine with PySequence_whateveryouwish now.


Alex
 
M

Matjaz

Alex, thanks. In the meantime I also found out what I
was doing wrong. One question, though. Would you
prefer using Py_BuildValue("") over Py_None and
increfing it?

Matjaz.
 
A

Alex Martelli

Matjaz said:
Alex, thanks. In the meantime I also found out what I
was doing wrong. One question, though. Would you
prefer using Py_BuildValue("") over Py_None and
increfing it?

Py_None with suitable incref is faster, Py_BuildValue is more compact,
not much in it either way.

Alex
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,206
Messages
2,571,069
Members
47,678
Latest member
Aniruddha Das

Latest Threads

Top