[Python-iterators] While we're at it...

Tim Peters tim.one at home.com
Sat Jun 30 22:28:41 EDT 2001


[Eduard Hiti]
> Could iterators be made slicable?

Sure.  We could give them .write() methods too <wink>.

> Then a 'fib()[3:6]' would give you the third to fifth fibonacci numbers.

As what, another iterator?  A list?  A tuple?

[Michael Hudson]
> I'm not sure that's a good idea, but I would like to see an
> "iterators" module that provided various common iterator
> manipulations, so you could have eg:
>
> def slice(it, lo, hi):
>     for i in range(lo):
>         it.next()
>     for i in range(hi - lo):
>         yield it.next()

The number of choices becomes mind-boggling, so prototype this module about
6 times first.  Like, who said slice should be a generator?  Maybe they want
an explicit list.  Maybe they don't want that iterating "it" after calling
slice() can change the values slice() *later* returns.  Maybe they want
slice() to return an indexable object too.  Etc.

The 2.2 test_generators.py has a cute class:

class LazyList:
    def __init__(self, g):
        self.sofar = []
        self.fetch = g.next

    def __getitem__(self, i):
        sofar, fetch = self.sofar, self.fetch
        while i >= len(sofar):
            sofar.append(fetch())
        return sofar[i]

    def clear(self):
        self.__dict__.clear()

This materializes an explicit list from an iterator, but doesn't compute
anything until you force it to by indexing with a value it hasn't seen
before; e.g., getting back to Eduard's example,

>>> def fibgen(a, b):
...
...     def sum(g, h):
...         while 1:
...             yield g.next() + h.next()
...
...     def tail(g):
...         g.next()    # throw first away
...         for x in g:
...             yield x
...
...     yield a
...     yield b
...     for s in sum(iter(fib),
...                  tail(iter(fib))):
...         yield s

>>> fib = LazyList(fibgen(1, 2))
>>> firstn(iter(fib), 17)
[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584]

where

def firstn(g, n):
    return [g.next() for i in range(n)]

Should probably derive that from UserList instead, to give it a full set of
list methods.  But then it's not clear what all of them should do.

Since there are so many possibilities, and so little Python experience here,
I'm very happy to leave the iterator protocol with the single method it
*must* have.  Anything beyond that is muddy at best, so better to leave it
alone at first.





More information about the Python-list mailing list