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

Carl Banks imbosol-1048700608 at aerojockey.com
Wed Mar 26 13:01:33 EST 2003


Maciej Kalisiak wrote:
> 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'>

Obviously, a problem with tp_new.


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

Here you've created a PyStateObject, or subclass thereof, namely self.
I'm not sure if you realize that type->tp_alloc creates the object.
It also creates an instance of the proper subclass.


> /*** 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;
> }

This function accepts a self argument, which was the newly created
object.  However, it doesn't use that argument at all.  Instead, it
creates it's own object, by calling PyObject_New, which does not
create an instance of the right subclass.  This is what 

The immediate solution is to replace the line "st = PyObject_New(...)"
with "st = tp->alloc(type,0)".  You'll have to change state_onew to
use type instead of self as its first parameter.  Then, delete the
line "self = tp->alloc(type,0)" from state_new.


Keep in mind that whatever object type->tp_new() returns is the object
that gets returned to Python as the "instance," whether it's an
instance of the type or not.


-- 
CARL BANKS






More information about the Python-list mailing list