We're back after a server migration that caused effbot.org to fall over a bit harder than expected. Expect some glitches.

Python's C API: Working with Sequences

Assorted notes on working with lists, tuples, iterators, and other sequences.

Passing Sequences to C Extensions

November 21, 2003 | Fredrik Lundh

Q. Is there a way to pass a variable-length list with flexible length to a C extension?

Summary: Use a PyObject* variable to hold the list object (use “O” for the type code), and use the sequence API to loop over the list contents.

Unless your sequences are really large (too large to hold in memory), the PySequence_Fast API is the most efficient way to extract the items. This API applies tuple() on the source, unless it’s already a tuple or a list, and uses direct access into the object structure to pick out individual items.

Here’s a sample snippet:


...

    PyObject* obj;
    PyObject* seq;
    int i, len;

    if (!PyArg_ParseTuple(args, "O", &obj))
        return NULL;

    seq = PySequence_Fast(obj, "expected a sequence");
    len = PySequence_Size(obj);
    for (i = 0; i < len; i++) {
        item = PySequence_Fast_GET_ITEM(seq, i);
        ...
        /* DON'T DECREF item here */
    }
    Py_DECREF(seq);

...

You can find plenty of examples in the source code for the standard library (grep for PySequence and look for GetItem, GET_ITEM, and Fast_GET_ITEM calls…)

You can also use the PyList API, but that only works for lists, and is only marginally faster than the PySequence_Fast API.

To squeeze out the last cycles from PySequence_Fast, expand the loop body yourself:

    seq = PySequence_Fast(obj, "expected a sequence");
    len = PySequence_Size(obj);
    if (PyList_Check(seq))
        for (i = 0; i < len; i++) {
            item = PyList_GET_ITEM(seq, i);
            ...
        }
    else
        for (i = 0; i < len; i++) {
            item = PyTuple_GET_ITEM(seq, i);
            ...
        }
    Py_DECREF(seq);

This design is as fast as a list-only implementation, but still supports tuples (fast) and other sequence objects, including arbitrary iterable objects (slower).

Here is a complete example: Help creating extension for C function