what should __iter__ return?

Thomas Jollans thomas at jollybox.de
Fri Sep 3 15:58:38 EDT 2010


On Friday 03 September 2010, it occurred to ernest to exclaim:
> Hi,
> 
> What is better:
> 
> def __iter__(self):
>     for i in len(self):
>         yield self[i]
> 
> or
> 
> def __iter__(self):
>     return iter([self[i] for i in range(len(self))])
> 
> The first one, I would say is more correct,
> however what if in a middle of an iteration
> the object changes in length? Then, the
> iterator will fail with IndexError (if items
> have been removed), or it will fail to iterate
> over the whole sequence (if items have
> been added).
> 
> What do you think?

Hmm. Modifying an object while iterating over it isn't a great idea, ever:

>>> L = [1,2,3,4]
>>> i = iter(L)
>>> next(i)
1
>>> next(i)
2
>>> del L[0]
>>> next(i)
4

You second version is wasteful. It creates a copy of the object just for 
iteration. I don't think that's something you should be doing. If you want 
"correct" behaviour as with lists, you might want something like this:

def __iter__(self):
    class _Iter:
        def __init__(it):
            it.i = -1

        def __next__(it):
            it.i += 1
            try:
                return self[it.i]
            except IndexError:
                raise StopIteration

    return _Iter()

> 
> Cheers.
> Ernest



More information about the Python-list mailing list