I l@ve RuBoard |
16.2 Implementing a Simple Extension TypeCredit: Alex Martelli 16.2.1 ProblemYou want to code and build a C extension type for Python with a minimal amount of hard work. 16.2.2 SolutionFirst of all, we need to create a setup.py using the distutils package (in Python 2.0 and later) to build and install our module: from distutils.core import setup, Extension setup(name = "elemlist", version = "1.0", maintainer = "Alex Martelli", maintainer_email = "[email protected]", description = "Sample, simple Python extension module", ext_modules = [Extension('elemlist',sources=['elemlist.c'])] ) Then we need an elemlist.c file with our module's source code: #include "Python.h" /* type-definition and utility-macros */ typedef struct { PyObject_HEAD PyObject *car, *cdr; } cons_cell; staticforward PyTypeObject cons_type; /* a type-testing macro (we don't actually use it here) */ #define is_cons(v) ((v)->ob_type == &cons_type) /* utility macros to access car and cdr, both as lvalues and rvalues */ #define carof(v) (((cons_cell*)(v))->car) #define cdrof(v) (((cons_cell*)(v))->cdr) /* ctor ("internal" factory function) and dtor */ static cons_cell* cons_new(PyObject *car, PyObject *cdr) { cons_cell *cons = PyObject_NEW(cons_cell, &cons_type); if(cons) { cons->car = car; Py_INCREF(car); /* INCREF when holding a PyObject */ cons->cdr = cdr; Py_INCREF(cdr); /* ditto */ } return cons; } static void cons_dealloc(cons_cell* cons) { /* DECREF when releasing previously held PyObject*'s */ Py_DECREF(carof(cons)); Py_DECREF(cdrof(cons)); PyObject_DEL(cons); } /* The Python type-object */ statichere PyTypeObject cons_type = { PyObject_HEAD_INIT(0) /* initialize to 0 to ensure Win32 portability */ 0, /*ob_size*/ "cons", /*tp_name*/ sizeof(cons_cell), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)cons_dealloc, /*tp_dealloc*/ /* implied by ISO C: all zeros thereafter, i.e., no other method */ }; /* module functions */ static PyObject* cons(PyObject *self, PyObject *args) /* the exposed factory function */ { PyObject *car, *cdr; if(!PyArg_ParseTuple(args, "OO", &car, &cdr)) return 0; return (PyObject*)cons_new(car, cdr); } static PyObject* car(PyObject *self, PyObject *args) /* car accessor */ { PyObject *cons; if(!PyArg_ParseTuple(args, "O!", &cons_type, &cons)) /* type-checked */ return 0; return Py_BuildValue("O", carof(cons)); } static PyObject* cdr(PyObject *self, PyObject *args) /* cdr accessor */ { PyObject *cons; if(!PyArg_ParseTuple(args, "O!", &cons_type, &cons)) /* type-checked */ return 0; return Py_BuildValue("O", cdrof(cons)); } static PyMethodDef elemlist_module_functions[] = { {"cons", cons, METH_VARARGS}, {"car", car, METH_VARARGS}, {"cdr", cdr, METH_VARARGS}, {0, 0} }; /* module entry point (module initialization) function */ void initelemlist(void) { /* Create the module with its functions */ PyObject *m = Py_InitModule("elemlist", elemlist_module_functions); /* Finish initializing the type objects */ cons_type.ob_type = &PyType_Type; } 16.2.3 DiscussionC-coded Python extension types have an undeserved aura of mystery and difficulty. Sure, it's a lot of work to implement every possible nicety, but a fundamental, useful type doesn't take all that much effort. This module is roughly equivalent to the Python-coded module: def cons(car, cdr): return car, cdr def car(conscell): return conscell[0] def cdr(conscell): return conscell[1] except that the C version contains about 25 times more lines of code, even excluding comments and empty lines (and it is not much faster than the Python-coded version, either). However, the point of this recipe is to demonstrate a minimal C-coded extension type. I'm not even supplying object methods (except the necessary destructor) but, rather, module-level functions for car and cdr access. This also shows the utter simplicity of building a C-coded extension module on any platform, thanks to the distutils package, which does all of the hard work. Because this is meant as an introduction to writing extension modules in C for Python, here are the instructions on how to build this extension module, assuming you have a Windows machine with Python 2.0 or later, and Microsoft Visual C++ 6 (or the free command-line equivalent that you can download from Microsoft's site as a part of their .NET Framework SDK). You can presumably translate mentally to other platforms such as Linux with gcc, for example. On the other hand, using non-Microsoft compilers on Windows takes more work, and I'm not going to cover that here (see http://www.python.org/doc/current/inst/non-ms-compilers.html). The steps are:
Now your new extension module is installed and ready! 16.2.4 See AlsoThe Extending and Embedding manual is available as part of the standard Python documentation set at http://www.python.org/doc/current/ext/ext.html; the Distributing Python Modules section of the standard Python documentation set is still incomplete, but it is the best source of information on the distutils package. |
I l@ve RuBoard |