[Python-Dev] Termination of two-arg iter()

Tim Peters tim.one@comcast.net
Tue, 16 Jul 2002 01:56:33 -0400


[Guido]
> While preparing a patch, I discovered something strange: despite the
> fact that listiter_next() never raises StopIteration when it returns
> NULL,

That much is a documented part of the tp_iternext protocol.

> and despite the fact that it is used as the implementation for
> the next() method,

Oops.

> calling iter(list()).next() *does* raise StopIteration, rather than a
> complaint about NULL without setting an exception condition.

That is surprising!

> It took a brief debugging session to discover that in the presence
> of a tp_iternext function, the type machinery adds a next method that
> wraps tp_iternext.  Cute, though unexpected!

It also explains an old mystery I never got around to investigating:

>>> print iter([]).next.__doc__
x.next() -> the next value, or raise StopIteration
>>>

That was a mystery because that's not the docstring attached to the list
iterator's next() method:

static PyMethodDef listiter_methods[] = {
        {"next",        (PyCFunction)listiter_next,     METH_NOARGS,
         "it.next() -- get the next value, or raise StopIteration"},

> It means that the implementation of various iterators can be a little
> simpler, because no next() implementation needs to be given.

I'm not sure that's a feature we always want to use.  Going thru a wrapper
function (a) adds another layer of function call, and (b) adds a

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

call via wrap_next().  Both expenses could be avoided if an existing next
method were left alone.  I suppose only the seoond expense is actually
"real", though, as most explicit xyz_next methods naturally call the
tp_iternext slot function anyway.  Still, when the body of a "next" method
is as simple as it is for lists, a call to PyArg_ParseTuple is a significant
overhead.