PyObject_New not running tp_new for iterators?

Gregory Bond gnb at itga.com.au
Wed Apr 20 04:11:12 EDT 2005


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.
>>>> import myiter
>>>> e = myiter.MyIter()
>>>> str(e)
> '<myiter.MyIter object at 0x184050>'
>>>> e.next()
> 0
>>>> e.next()
> 1
>>>> e.next()
> 2
>>>> e.next()
> 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!

>>>> f = myiter.FromFile()
>>>> f
> <myiter.MyIter object at 0x184070>
>>>> f.next()
> -2080374694
>>>> f.next()
> -2080374693
>>>> f.next()
> -2080374692
>>>> 

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?



More information about the Python-list mailing list