PyStructSequence: creating named tuples in C

I’m not a big fan of namedtuples in Python, but sometimes they are useful.

For example, sys.version_info returns a named tuple (starting with Python 2.7):

sys.version_info(major=2, minor=7, micro=2, releaselevel='final', serial=0)

This means that in order to check the major number you may do sys.version_info[0] or sys.version_info.major. Of course, the latter is more readable.

You can use collections.namedtuple in order to create a named tuple in Python, but what if you want to create such an object in a C extension module?

I found myself diving the CPython source looking for this, and I found it: PyStructSequence. There is not documentation for it at the moment, but there is an issue open for it here. It’s not very complex to use, but I created a very simple example:

# coding=utf8
from distutils.core import setup, Extension
setup(name = "foo",
version = "0.0.1",
author = "Saúl Ibarra Corretgé",
author_email = "saghul@gmail.com",
description = "PyStructSequence example",
ext_modules = [Extension('foo',
sources = ['test_pystructsequence.c'],
)]
)
view raw setup.py hosted with ❤ by GitHub
#include "Python.h"
#include "structmember.h"
#include "structseq.h"
static PyTypeObject FooResultType = {0, 0, 0, 0, 0, 0};
static PyStructSequence_Field foo_result_fields[] = {
{"field_1", "This is field 1"},
{"field_2", "This is field 2"},
{"field_3", "This is field 3"},
{NULL}
};
static PyStructSequence_Desc foo_result_desc = {
"foo_result",
NULL,
foo_result_fields,
3
};
PyMODINIT_FUNC
initfoo(void)
{
PyObject *foo = Py_InitModule("foo", NULL);
if (FooResultType.tp_name == 0)
PyStructSequence_InitType(&FooResultType, &foo_result_desc);
Py_INCREF((PyObject *) &FooResultType);
PyModule_AddObject(foo, "foo_result", (PyObject *) &FooResultType);
}

The example shows how a PyStructSequence is created and exposed in a module. Operations with this types of objects are very similar to those with regular tuples (in C), so in order to set an item you’d do the following:

PyStructSequence_SET_ITEM(my_named_tuple, 0, PyString_FromString("content for field 0"));
PyStructSequence_SET_ITEM(my_named_tuple, 1, PyString_FromString("content for field 1"));
...

That’s about it, in case you want to dive deeper I recommend having a look at Modules/posixmodule.c in the CPython source code and checking how stat_result is defined.

:wq