beginning index for generators

Peter Otten __peter__ at web.de
Sat Oct 16 17:03:46 CEST 2004


kosh wrote:

> I was wondering if there is or there could be some way to pass a generator
> an optional starting index so that if it supported that slicing could be
> made more efficient. Right now if you do use a generator and do a
> [100:110] or any other kind of slice it reads all the values up to 100
> also.

Here is an 'iterate' class that decides whether to use iteration over or
indexed access of items based on the existence of a __getitem__() method.
It's mostly a proof of concept and not tested beyond what you see below.

Peter

import itertools, sys

def irange(start, stop, step):
    if start is None:
        start = 0
    if step is None: 
        step = 1
    index = start
    if stop is None:
        while True:
            yield index
            index += step
    else:
        if step < 0:
            while index > stop:
                yield index
                index += step
        else:
            while index < stop:
                yield index
                index += step

def islice(iterable, start, step, stop):
        if start is None: start = 0
        if step is None: step = 1
        return itertools.islice(iterable, start, stop, step)
        
class iterate(object):
    def __init__(self, iterable):
        self.iterable = iterable
    def __getitem__(self, s):
        if not isinstance(s, slice):
            raise ValueError("supports only slices")
        start, stop, step = s.start, s.stop, s.step
        if hasattr(self.iterable, "__getitem__"):
                indexable = self.iterable
                def iterate():
                    for index in irange(start, stop, step):
                        yield indexable[index]
                return iterate()
        return islice(self.iterable, start, step, stop)

class Sequential(object):
    def __init__(self):
        self.index = 0
    def __iter__(self):
        return self
    def next(self):
        print "sequential[%s]" % self.index
        try:
            return self.index
        finally:
            self.index += 1

class Random(Sequential):
    def __getitem__(self, index):
        print "random[%s]" % index
        return index


def printThem(iterable):
    for i in iterable:
        print i
    print "---"

printThem(iterate(Random())[3:10:2])
printThem(iterate(Random())[3:10])
printThem(iterate(Sequential())[3:10:2])
printThem(iterate(Sequential())[3:10])
# I'd rather not:
# printThem(iterate(Sequential())[sys.maxint-10::3])
printThem(itertools.islice(iterate(Random())[sys.maxint-5::3], 10))




More information about the Python-list mailing list