Extending & Embedding Python Using C - A First Module |
Written by Mike James | ||||
Tuesday, 05 March 2024 | ||||
Page 2 of 3
The example of the arith module used in the previous chapters is a simple module which provides a single function add(a,b) and we can initialize it using the steps just described. First we need to define the functions and methods it provides: static PyMethodDef AddMethods[] = { {"add", add, METH_VARARGS, "add two numbers"}, {NULL, NULL, 0, NULL} // sentinel }; PyMethodDef defines the function that we can call: {"add", add, METH_VARARGS, "add two numbers"} The first field is the name that the Python program uses to call the function and the second is a pointer to the C function that is called. Notice that the two don’t have to be the same. For example: {"sum", add, METH_VARARGS, "add two numbers"} would mean that the C function add in the module was called when the Python function sum was called. The third field METH_VARARGS specifies that the parameters are passed as a tuple. The final field is the docstring. Now that we have the method definitions, we can create the PyModuleDef struct: static struct PyModuleDef addmodule = { PyModuleDef_HEAD_INIT, "arith", "C library for sum", -1, AddMethods }; The name of the module is “arith” and the AddMethods struct contains the information about what function are available. Now all that remains is to write the add function so that it can be called by the C API. The only real difference between this and a simple add function: int add(int x, int y){ return x+y; } is the need to work with PyObject as the parameter type and the return type and the need to convert the data from Python format and back to Python format. static PyObject * add(PyObject *self, PyObject *args) The parameters passed to the function are both PyObjects – the first is self, which in this case is just a pointer to the module object, which is of course just a PyObject. The second is a tuple of the parameters passed to the function in Python. Our next problem is to extract the parameters into data types that C can use. In most cases this is a job for one of the PyArg functions. PyArg_ParseTuple(args, format, variables) will take the tuple pointed at by args and use the specified format to split it into different data types which are stored in the specified variables. This is very similar to the way printf uses a format to print different variables types, although the format codes used are different. In this case, the two arguments are integers and the appropriate format is “ii”. PyArg_ParseTuple(args, "ii", &x, &y) stores the two integer arguments in x and y ready for use by the C function. The function returns false if there is an error and returns NULL to signal the error to Python. Once we have the values we can add them and convert them into a form that Python can use via the PyLong_FromLong function. This is typical. The C function that you want to make available to Python generally needs the Python objects it is passed to be converted to C data types and then any results it produces need to be converted into suitable Python objects. The complete program has been presented earlier, but it is worth repeating: #define PY_SSIZE_T_CLEAN In book but not in this extract
|
||||
Last Updated ( Tuesday, 05 March 2024 ) |