Unpacking a python list in C?
Michael Hudson
mwh at python.net
Fri May 3 07:14:24 EDT 2002
Ken Seehof <kseehof at neuralintegrator.com> writes:
> Here's some real code that's pretty close to what you want. You can
> use PyList_* instead of PySequence_* if speed is more important than
> flexibility (PySequence works with any sequence object).
> This example is a little different than what you requested (it's a
> working python extension function). But it does show how to iterate
> a python list.
>
> /////////////////////////
> // syntax: obj = manifold([seq])
> // returns: new manifold object
> //
> // Creates a manifold object, and initializes with sequence
Are you not doing any error checking for clarity?
> static PyObject *module_manifold(PyObject *self, PyObject *args)
> {
> PyObject *seq = NULL;
> if (!PyArg_ParseTuple(args, "|O", &seq)) return NULL;
It would be wise to check that "seq" is indeed a sequence at some
point...
Also, if you call this function with no argument it will return NULL
but with no exception set... don't do that.
> manifold__object *k = manifold__new();
>
> if (seq)
> {
> for (int i=0; i<PySequence_Length(seq); i++)
Also PySequence_Length isn't reliable; consider
class Devious:
def __len__(self):
return 9
def __getitem__(self, i):
raise IndexError
> {
> PyObject *obj = PySequence_GetItem(seq, i);
> manifold__insert_obj(k, k->root, obj);
... so obj could be NULL here; manifold__insert_obj will likely try to
INCREF it... boom!
> }
> }
>
> return (PyObject *)k;
> }
The best way to nullify the threat of such devious code is to use the
"PySequence_Fast" API, like so:
static PyObject *module_manifold(PyObject *self, PyObject *args)
{
PyObject *seq;
int len;
if (!PyArg_ParseTuple(args, "O", &seq)) return NULL;
manifold__object *k = manifold__new();
seq = PySequence_Fast(seq, "manifold: sole argument must be sequence");
if (!seq) return NULL;
len = PySequence_Fast_GET_SIZE(seq);
for (int i=0; i < len; i++) {
PyObject *obj = PySequence_Fast_GET_ITEM(seq, i);
manifold__insert_obj(k, k->root, obj);
}
return (PyObject *)k;
}
as PySequence_Fast knows how to cope with the most devious of user
classes. I'm not sure when it appeared (I don't *think* it's in
1.5.2, unfortunately, though there's always the option of wholesale
lifting of code from Python's codebase to your own).
Docs here:
http://www.python.org/dev/doc/devel/api/sequence.html
Mild apologies for picking on Ken's code like this; more people should
know about this API, though.
Cheers,
M.
--
The Programmer's Quick Guide To Python (Time Machine version):
You try to shoot yourself in the foot, only to realize that
there's no need, since Guido thoughtfully shot you in the foot
years ago. -- Nick Mathewson, comp.lang.python
More information about the Python-list
mailing list