subclassing a new-style (C) extension type: help!

Maciej Kalisiak mac at die.spammer.die.dgp.toronto.edu
Wed Mar 26 11:45:10 EST 2003


Hello,

I'm trying to write an extension type in C that I can later subclass in Python,
but not having much luck, and I would greatly appreciate any nudges in the
right direction.  My current problem is this:

>>> from Base import Base	     # the extension in C
>>> class Derived(Base):
...     pass
...
>>> i = Derived(1)		     # constructor takes one arg
>>> type(i)
<type 'Base'>

So it would seem from the above that derivation of my extension type is not
working.

Now, I tried to find some template/example code for writing such extension
types, but I only found bits and pieces of information in newsgroups, the
rather heavy-reading PEP253, and Guido's "Unifying types and classes in Python
2.2".  Being used to the classic style types/classes, I'm still quite a bit
confused with this new, more complex way of doing it.  In fact, I'm *porting*
this module from classic-style, rather than writing it from scratch.

Here are the more important bits of the C code defining this base type (it's
actually called "State", not "Base"):


PyTypeObject PyState_Type = {
  PyObject_HEAD_INIT(NULL)
  0,
  "State",			/* tp_name */
  sizeof(PyStateObject),	/* tp_basicsize */
  0,				/* tp_itemsize */
  state_dealloc,		/* tp_dealloc */
  0,				/* tp_print */
  state_getattr,		/* tp_getattr */
  0,				/* tp_setattr */
  0,				/* tp_compare */
  state_repr,			/* tp_repr */
  0,				/* tp_as_number */
  &state_as_sequence,		/* tp_as_sequence */
  0,				/* tp_as_mapping */
--- snip ---
  0,				/* tp_as_buffer */
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
  0,				/* tp_doc */
--- snip ---
  0,				/* tp_init */
  PyType_GenericAlloc,		/* tp_alloc */
  state_new,			/* tp_new */
  state_free,			/* tp_free */
};


static PyMethodDef module_methods[] = {
  { NULL, NULL }
};


static PyMethodDef State_methods[] = {
  { "copy", state_copy, METH_VARARGS },
  { NULL, NULL, 0, NULL }	/* sentinel */
};


DL_EXPORT(void)
initState(void)
{
  PyObject *mod, *d;

  PyState_Type.ob_type = &PyType_Type;
  mod = Py_InitModule("State", module_methods);

  if(PyType_Ready(&PyState_Type) < 0)
    return;

  d = PyModule_GetDict(mod);
  PyDict_SetItemString(d, "State", (PyObject*)&PyState_Type);  
}

--- here are some of the slot functions ---

PyObject*
state_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
{
  PyObject *self;
  self = type->tp_alloc(type, 0);
  return state_onew(self, args);
}


static
void
state_free(PyObject* self)
{
  state_t* p;
  p = PyState_AsData(self);
  free(p->elems);
  free(p);
  PyObject_Del(self);
}


static
void
state_dealloc(PyObject* self)
{
  state_free(self);
}

/*** Please excuse the kludginess here.  This is a piece of code from classic
     style classes, and needs to be refactored.  It is strongly influenced
     by the function "new_noddy" from the Python docs on extending. ***/

PyObject*
state_onew(PyObject* self, PyObject* args)
{
  PyStateObject* st;
  int st_size;
  state_t* p;

  if (!PyArg_ParseTuple(args, "i:state_onew", &st_size))
    return NULL;

  st = PyObject_New(PyStateObject, &PyState_Type);

  if (!st)
    return PyErr_NoMemory();
  
  st->_p = (state_t*)malloc(sizeof(state_t));
  p = st->_p;
  if (!p)
    return PyErr_NoMemory();

  p->state_size = st_size;
  p->elems = (float*)malloc(sizeof(float)*st_size);

  if (!p->elems)
    return PyErr_NoMemory();

  memset(p->elems, 0, sizeof(float)*st_size);

  return (PyObject*)st;
}


Any hints, suggestions, *pointers to example code!* would be most appreciated.

Also, a wishlist item: it would really help some of the more casual Python-
extending users, such as myself, if the "noddy" example from the Python docs
was rewritten for the new style classes.  Following an example is far easier
than first trying to form a complete and coherent picture in one's head of
everything that's going on.




More information about the Python-list mailing list