static.
It is useless to populate the global C name-space by exporting symbols
needlessly.
To create a module, you need a name and an initialization routine, to be called by Python.
PyMethodDef methods[] = {
{NULL, NULL},
};
void initmodname()
{
(void)Py_InitModule("modname", methods);
}
Unfortunately, you cannot pass NULL instead of methods.
Create a function that takes Python objects and returns a pointer to a Python object.
PyObject *MyCommand(self, args)
PyObject *self, *args;
{ PyObject *result = NULL;
long a, b;
if (PyArg_ParseTuple(args, "ii", &a, &b)) {
result = Py_BuildValue("i", a + b);
} /* otherwise there is an error,
* the exception already raised by PyArg_ParseTuple, and NULL is
* returned.
*/
return result;
}
PyMethodDef methods[] = {
{"add", MyCommand, METH_VARARGS},
{NULL, NULL},
};
The arguments are passed as a Python tuple object, decoded with
PyArg_ParseTuple(). For functions, self will be
NULL; it points to the bound object for a method.
Each element in the methods array is a structure containing the string
name in the module of the function, the C function, and how to pass
the arguments (we will get to that later).
To add a function later, edit the methods array inserting the line. Since the module name-space is a dictionary, the order of the entries is up to the coder's best judgment.
You added a constant by creating a Python object and binding it to the module name-space. Since the module global name-space is a dictionary, modification is the same way.
void initmodname()
{ PyObject *m, *d;
PyObject *tmp;
m = Py_InitModule("modname", methods);
d = PyModule_GetDict(m);
tmp = PyFloat_AsDouble(3.1415926);
PyDict_SetItemString(d, "pi", tmp);
Py_DECREF(tmp);
}
If you wish to use the object in the C code, then declare a global
(within the C file) and assign to that variable instead of
tmp.
Often you will want to make an exception type for your module.
PyObject *exception = NULL;
...
void initmodname()
{ PyObject *m, *d;
...
#if PYTHON_API_VERSION >= 1007
exception = Py_NewException("modname.error", NULL, NULL);
#else
exception = Py_BuildValue("s", "modname.error");
#endif
PyDict_SetItemString(d, "error", exception);
}
The C preprocessor directive creates exception classes in Python 1.5,
or later and string exceptions in earlier releases.
At this point, you can raise exceptions with the normal Python API.
PyErr_SetString(exception, "I could not do that");
For the sake of explanation, I will build a small (fairly useless) object that autoincrements and emulates a number otherwise.
One important point: You will not want to emulate both a sequence and a mapping. There are overlapping callback methods between the two. The more generic is a mapping, and the implementation is still up to the coder.
Create normal C structure with the exception of a Python header,
by including PyObject_HEAD.
typedef struct {
PyObject_HEAD
long value;
} counter;
Just about all the Python types follow this form. It defines the behavior of the type; for example, do we treat it as a dictionary?
PyTypeObject counter_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"counter", /* char *tp_name; */
sizeof(counter), /* int tp_basicsize; */
0, /* int tp_itemsize; /* not used much */
counter_dealloc, /* destructor tp_dealloc; */
counter_print, /* printfunc tp_print; */
counter_getattr, /* getattrfunc tp_getattr; /* __getattr__ */
counter_setattr, /* setattrfunc tp_setattr; /* __setattr__ */
counter_compare, /* cmpfunc tp_compare; /* __cmp__ */
counter_repr, /* reprfunc tp_repr; /* __repr__ */
&counter_as_number, /* PyNumberMethods *tp_as_number; */
0, /* PySequenceMethods *tp_as_sequence; */
0, /* PyMappingMethods *tp_as_mapping; */
counter_hash /* hashfunc tp_hash; /* __hash__ */
0, /* ternaryfunc tp_call; /* __call__ */
counter_str, /* reprfunc tp_str; /* __str__ */
};
It is often useful to create C macros that access the object inside the module.
The#define Counter_Check(v) ((v)->ob_type == &counter_Type) #define Counter_value(v) (((counter *)(v))->value)
Counter_value macro implicitly casts the object
appropriately.
PyObject *
counter_NEW(initial_value)
long initial_value;
{ counter *object = NULL;
object = PyObject_NEW(counter, &counter_Type);
if (object != NULL)
object->value = initial_value;
return (PyObject *)object;
}
void
counter_dealloc(self)
PyObject *self;
{
PyMem_DEL(self);
}
/* this is the Python constructor, as opposed to the C constructor */
/* this is a normal module function */
PyObject *
counter_new(self, args)
PyObject *self, *args;
{ PyObject *object = NULL;
long value = 0; /* default initial value */
if (PyArg_ParseTuple(args, "|i", &value))
object = counter_NEW(value);
return object;
}
You will usually want to create two constructors. One to be used
internally that does not require a Python tuple argument list
and the other to be registered as a Python function to be called by
the Python interpreter.
The destructor is registered in the tp_dealloc slot of
the PyTypeObject definition (above). When the reference count goes
to zero, the destructor is called.
PyObject *counter_getattr(self, attrname)
PyObject *self;
char *attrname;
{ PyObject *result = NULL;
counter *object = (counter *)self;
if (strcmp(attrname, "value") == 0)
result = PyInt_AsLong(object->value);
else
PyErr_SetString(PyExc_AttributeError, attrname);
return result;
}
/* the C setattr function should return an integer, 0 on success, -1
when an exception is raised. When the given value is NULL, then
"delattr" was called instead of "setattr".
(Remember Python's None is Py_None, not NULL)
*/
int counter_setattr(self, attrname, value)
PyObject *self, *value;
char *attrname;
{ int result = -1;
counter *object = (counter *)self;
long newval;
/* we will let the user reset the value, just for show */
if (strcmp(attrname, "value") == 0) {
if (value != NULL) {
if (PyArg_Parse(value, "i", &newval)) {
object->value = newval;
result = 0; /* success */
} /* an exception is raised */
} else /* a `del obj.value' statement */
PyErr_SetString(PyErr_TypeObject, "read-only attribute");
} else
PyErr_SetString(PyExc_AttributeError, attrname);
return result;
}
Defining a method is a combination of defining a module function
(which uses its self argument)
and returning a data attribute.
PyObject *
counter_incr(self, args)
PyObject *self, *args;
{ PyObject *result = NULL;
counter *object = (counter *)self;
if (PyArg_ParseTuple(args, "")) { /* takes no args, other than self */
object->value++;
result = Py_None;
Py_INCREF(result);
}
return result;
}
PyMethodDef counter_methods[] = {
{"incr", counter_incr, METH_VARARGS},
{NULL, NULL},
};
PyObject *counter_getattr(self, attrname)
PyObject *self;
char *attrname;
{ PyObject *result = NULL;
counter *object = (counter *)self;
if (strcmp(attrname, "value") == 0)
result = PyInt_AsLong(object->value);
else /* find and return a bound method */
result = Py_FindMethod(counter_methods, self, attrname);
return result;
}
Notice how the counter_getattr function changed. Also notice how
little difference between methods and module functions there is.
There may be times when you want to make an object callable. The method is similar for normal functions, but the keyword arguments must be handled (which are only optional with normal functions).
PyObject *
counter_call(self, args, keywds)
PyObject *self, *args, *keywds;
{ PyObject *result = NULL;
counter *object = (counter *)self;
static char *kwlist[] = { NULL }; /* no keywords */
/* check that there are no passed arguments or keywords */
if (keywds == NULL ?
PyArg_ParseTuple(args, "") :
PyArg_ParseTupleAndKeywords(args, keywds, "", kwlist))
PySys_WriteStdout("The value of the counter is %d.\n", object->value);
result = Py_None;
Py_INCREF(result);
}
return result;
}
int counter_compare(self, other)
PyObject *self, *other;
{ int result = 0;
counter *object = (counter *)self;
PyObject *tmp;
tmp = PyInt_FromLong(object->value);
result = PyObject_Compare(tmp, other);
Py_DECREF(result);
return result;
}
long
counter_hash(self)
PyObject *self;
{ counter *object = (counter *)self;
PyObject *temp;
long result = -1
temp = PyInt_FromLong(object->value);
if (temp == NULL)
result = PyObject_Hash(temp);
Py_XDECREF(temp);
return result;
}
This is a simple example, but shows the basic desire:
convert to a Python object and compare.
Otherwise, you will need to perform the comparison manually,
possibly with type checking (eg. string versus integer comparisons).
There are three methods of printing an object.
They relate to print a, repr(a) and
str(a)
int counter_print(self, fp, flags)
PyObject *self;
FILE *fp;
int flags; /* can be ignored in Python 1.5.x and earlier */
{ counter *object = (counter *)self;
fprintf(fp, "%d", object->value);
return 0;
}
PyObject *counter_repr(self)
PyObject *self;
{ counter *object = (counter *)self;
char buf[100];
sprintf(buf, "<counter %d>", object->value);
return PyString_FromString(buf);
}
PyObject *counter_str(self)
PyObject *self;
{ counter *object = (counter *)self;
char buf[100];
sprintf(buf, "%d", object->value);
return PyString_FromString(buf);
}
The repr and str methods return Python string objects, but the print
method writes directly to the given opened file.
If the representation of the object is to be the same in all modes,
then define a "repr" method and define the others as NULL.
With the exception of "initmodname()", just about every other symbol can be declared static.
Here is a list of the prototypes used in type and method definitions. This should help you write the appropriate functions yourself.
void (*destructor)
(PyObject *self);
int (*printfunc)
(PyObject *self, FILE *fp, int flags);
PyObject *(*getattrfunc)
(PyObject *self, char *attrname);
int (*setattrfunc)
(PyObject *self, char *attrname, PyObject *value);
int (*cmpfunc)
(PyObject *v, PyObject *w);
PyObject *(*reprfunc)
(PyObject *self);
long (*hashfunc)
(PyObject *self);
int (*inquiry)
(PyObject *self);
int (*coercion)
(PyObject **v, **w);
PyObject *(*intargfunc)
(PyObject *self, int i);
PyObject *(*intintargfunc)
(PyObject *self, int il, int ih);
int (*intobjargproc)
(PyObject *self, int i, PyObject *value);
int (*intintobjargproc)
(PyObject *self, int il, int ih, PyObject *value);
int (*objobjargproc)
(PyObject *self, PyObject *i, PyObject *value);
PyObject *(*unaryfunc)
(PyObject *self);
PyObject *(*binaryfunc)
(PyObject *self, PyObject *obj);
PyObject *(*ternaryfunc)
(PyObject *self, PyObject *args, PyObject *keywds);