2.4.1 From Python to C

In many extension functions, you can use the argument processing function PyArg_ParseTuple to check the types of the arguments passed to your function and extract values in a format more usual to C programs.

For instance, here's a module that implements type-specific addition functions (there's not much point to this, but never mind):

#include <Python.h>

static char third_doc[] = 
"This module is just a simple example.";

static PyObject*
third_addi(PyObject *self, PyObject *args)
{
	long a, b;
	
	if (!PyArg_ParseTuple(args, "ll:addi", &a, &b)) {
		return NULL;
	}

	return PyInt_FromLong(a + b);
}

static char third_addi_doc[] = 
"addi(a, b) -> int\n\
\n\
Return the sum of integers a and b.";

static PyObject*
third_addf(PyObject *self, PyObject *args)
{
	double a, b;
	
	if (!PyArg_ParseTuple(args, "dd:addf", &a, &b)) {
		return NULL;
	}

	return PyFloat_FromDouble(a + b);
}

static char third_addf_doc[] = 
"addf(a, b) -> floats\n\
\n\
Return the sum of floats a and b.";

static PyMethodDef third_methods[] = {
	{"addi", third_addi, METH_VARARGS, third_addi_doc},
	{"addf", third_addf, METH_VARARGS, third_addf_doc},
	{NULL, NULL}
};

PyMODINIT_FUNC
initthird(void)
{
	Py_InitModule3("third", third_methods, third_doc);
}

The main novelty here is the use of the PyArg_ParseTuple function. This function (like PyArg_UnpackTuple) takes a variable number of arguments:

  1. args: An argument tuple.
  2. format: A format string, usually ending in a colon and the name of the function, which can appear in error messages.
  3. ...: A variable number of arguments, the type and number of which are determined by format.

PyArg_ParseTuple is quite a complex function and no attempt to describe every intricacy is made here.

In common usage, each character of the format string indicates that the correspending varadic argument is a pointer to a given C type and PyArg_ParseTuple will attempt to convert the corresponding Python-level positional argument to that type and store this value into the given pointer.

So, in the function third_addi in the above module, "ll" declares that the final two arguments are pointers to C variables of long type. Attempting to pass a value that cannot be implicitly converted to a Python integer - a string or a file, say - will result in PyArg_ParseTuple setting an exception and returning 0. Conversely, passing integers or instances of a user defined class that defines an __int__ method stores the integer values obtained from these objects in the C variables a and b (Python integers are implemented using C longs, so long is the most natural type to use here).

Here's a list of a few of the simpler format codes:

Code C type
"l" long
"i" int
"d" double
"f" float
"s" char * (a C string)
"O" PyObject *
"|" indicates that the following arguments are optional.

For more details, please see the fine documentataion XXX link!.

A final note is that parsing the format code on each invocation of the function takes time. If the call to PyArg_ParseTuple isn't doing much - if you aren't taking advantage of the type checking and processing it provides - a call to PyArg_UnpackTuple is probably clearer and more efficient.

One could get the impression from the above that every function in an extension module must call one of PyArg_UnpackTuple or PyArg_ParseTuple. Nothing could further from the truth! But, like functions you define in Python, almost all extension functions you write in fact take a fixed number of arguments, and using one of the PyArg_ API functions is a more convenient - and conventional - way of checking the arguments for validity than doing it by hand.

THIS DOCUMENT IS A DRAFT! Comments to mwh@python.net please.