Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] - نسخه متنی

David Ascher, Alex Martelli, Anna Ravenscroft

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


Recipe 17.1. Implementing a Simple Extension Type


Credit: Alex Martelli


Problem



You want to code and build a C
extension type for Python with a minimal amount of hard work.


Solution


First of all, we need to create a setup.py file
to use the distutils package to build and install
our module:

from distutils.core import setup, Extension
setup(name = "elemlist",
version = "1.0",
maintainer = "Alex Martelli",
maintainer_email = "amcx@aleax.it",
description = "Sample, simple Python extension module",
ext_modules = [Extension('elemlist',sources=['elemlist.c'])]
)

Then, we need a file elemlist.c 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,
as either lvalues or 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(cons->car); Py_DECREF(cons->cdr);
PyObject_Del(cons);
}
/* A minimal 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 PyObject*
setcar(PyObject *self, PyObject *args) /* car-setter */
{
PyObject *cons;
PyObject *value;
if(!PyArg_ParseTuple(args, "O!O", &cons_type, &cons, &value))
return 0;
Py_INCREF(value);
Py_DECREF(carof(cons));
carof(cons) = value;
return Py_BuildValue(");
}
static PyObject*
setcdr(PyObject *self, PyObject *args) /* cdr-setter */
{
PyObject *cons;
PyObject *value;
if(!PyArg_ParseTuple(args, "O!O", &cons_type, &cons, &value))
return 0;
Py_INCREF(value);
Py_DECREF(cdrof(cons));
cdrof(cons) = value;
return Py_BuildValue(");
}
static PyMethodDef elemlist_module_functions[ ] = {
{"cons", cons, METH_VARARGS},
{"car", car, METH_VARARGS},
{"cdr", cdr, METH_VARARGS},
{"setcar", setcar, METH_VARARGS},
{"setcdr", setcdr, 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;
}


Discussion


C-coded Python extension types have an undeserved aura of mystery and
difficulty. Sure, it's a lot of work to implement
every possible feature, but a minimal yet useful type
doesn't necessarily 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]
def setcar(conscell, value): conscell[0] = value
def setcdr(conscell, value): conscell[1] = value

except that the C source is about 25 times larger, 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 indispensable destructor) but, rather, I am
providing module-level functions to build cons
cells and to read and write their car and
cdr fields. This recipe 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.

Lisp-savvy readers will have recognized from the names involved that
this little extension offers the core functionality to implement a
Lisp-like linked list typeusing some NIL
marker (e.g. None), by convention, as the
cdr of the last cons-cell of a
list, and otherwise "consing up a
list" by having every cdr be
another cons-cell. You might easily
constrain the cdr to be
either None or another
cons-cell, giving up on generality for a bit of
extra error checking.

Because this recipe is meant as an introduction to writing extension
modules in C for Python, here are the instructions for building this
extension module, assuming you have a Windows machine with Python 2.3
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, Mac OS X
with gcc, and so on. On the other hand, using
different C compilers on Windows involves more work, and
I'm not going to cover that here (see http://sebsauvage.net/python/mingwl).

Here are the steps you should follow to build this
recipe's extension:

  1. Make a new directoryfor example,
    C:\Temp\EL.

  2. Open a command-prompt window, and go to the new directory.

  3. In the new directory, create the files setup.py
    and elemlist.c with the contents of the
    recipe's text.

  4. Run the following at the command prompt (assuming
    you've performed a standard Python 2.3 installation,
    so that your python.exe lives in
    C:\Python23):

    <m>C:\Temp\EL> C:\Python23\python setup.py install</m>

  5. This command will result in lots of output, which you should examine
    to check for problems. Presumably, all has gone well, and the new
    elemlist extension module has been built and
    installed.

  6. Now try the extension by running the following at the DOS prompt:

    <m>C:\Temp\EL> C:\Python23\python</m>
    (snipped: various greeting messages from Python)
    >>> from elemlist import cons, car, cdr
    >>> a = cons(1, cons(2, cons(3, ( ))))
    >>> car(cdr(a))
    2
    >>>

Thereyour new extension module is installed and ready!


See Also


The Extending and Embedding manual is
available as part of the standard Python documentation set at
http://www.python.org/doc/current/ext/extl;
the section "Distributing Python
Modules" of the standard Python documentation set is
still incomplete, but it's a reliable source of
information on the distutils package.
Python in a Nutshell covers the essentials of
extending and embedding and of the distutils
package.

/ 394