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