PyObject_New not running tp_new for iterators?

G

Gregory Bond

I'm trying to extend Python with an iterator class that should be
returned from a factory function.

For some reason the iterator object is not being properly initialised if
the iterator is created in a C function. It works just fine if the
object is created using the class contructor

Trying to minimise the cut-n-paste, but:
typedef struct {
PyObject_HEAD

int i;

} MyIter;


static PyObject *
MyIter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
MyIter *self;

self = (MyIter *)type->tp_alloc(type, 0);
if (self) {
self->i = 0;
}

return (PyObject *)self;
}

static PyObject *
MyIter_Iter(PyObject *self)
{
Py_INCREF(self);
return self;
}

static PyObject *
MyIter_Next(PyObject *self)
{
MyIter *ep = (MyIter *) self;
return Py_BuildValue("i", ep->i++);
}


plus the usual type stucture. This simple iterator returns the integers
from 0 to (programmer's) infinity.

This works fine if I create the object directly:
Python 2.3.1 (#3, Oct 1 2003, 16:18:11)
[GCC 3.3] on sunos5
Type "help", "copyright", "credits" or "license" for more information.3

However, if I create the MyIter object from a C factory function:
static PyObject *
FromFile(PyObject *self, PyObject *args)
{
MyIter *ro;

if (!PyArg_ParseTuple(args, ""))
return NULL;

if (!(ro = PyObject_New(MyIter, &MyIterType)))
return NULL;

return (PyObject *)ro;
}

static PyMethodDef My_methods[] = {
{"FromFile", FromFile, METH_VARARGS,
"Return an iterator."},
{NULL} /* Sentinel */
};

then the MyIter object is not properly initialised!

I tried a similar problem with a plane-old-object using tp_members
(rather than an iterator object) and that worked fine, even from a
factory function.

I've looked long and hard at the API doc, but I'm stumped..... I've
checked a couple of examples and they just do what I'm doing!

What am I missing?
 
G

Gregory Bond

I wrote:

[snip]
> What am I missing?

The fundamental problem is that this:

is really only a malloc() - it doesn't call the tp_new function at all.
This is not really clear in the 2.3 version of the C API document that
I was consulting - the 2.4 version is much clearer.

I have no idea how to do in C all the things that calling a class
constructor in Python does. Am I supposed to be calling tp_new &
tp_init directly?

In the end, this particular class really only needs to be created from a
factory function, so I removed the tp_new member altogether and just
wrote a C function to initialise the object, and called that from the C
factory function.

[The above is not particular to the fact that my class is an iterator -
all C classes have the same behaviour. My test of a plain-old class
probably looked like it worked due to lucky memory patterns.]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top