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:
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.