[Tutor] PolyRange -- iterator

spir denis.spir at free.fr
Wed Nov 4 17:38:48 CET 2009


Hello,

as I was crawling in endless complications with unadequate ranges, I decided to create a "PolyRange" type able to hold arbitrary many "sub-range"; which means finally a big range with wholes in it. This whole stuff again to cope with unicode -- a poly-range would be able to hold a range for a char class (eg 'letter') which spans over several ordinal ranges. (Viva unicode consortium!)

So, it works as needed. It is even able to "stretch" over addictional sub-ranges or to "unite" with a poly-range brother (sister, too). See code below.

Now, I need it to be properly iterable if needed -- the main use beeing indeed the 'in' operator -- but who knows. So, I tried to implement __iter__ and next (by the way, why isin't it called __next__ instead, looks strange for a python builtin?). Seems to work, but the result looks veeery heavy to my eyes. As I had never written an iterator before, would be nice and criticize the code?

Thank you,
Denis
-------
la vita e estrany



==========================================================
class PolyRange(object):
    def __init__(self, *bounds):
        ''' Build list of ranges from bounds.
            * bounds must sequence of (n1,n2) pairs. '''
        self.bounds = list(bounds)
        self.ranges = [xrange(n1,n2) for (n1,n2) in bounds]
        # iteration
    def __contains__(self, item):
        ''' x in self '''
        for range in self.ranges:
            if item in range:
                return True
    def __or__(self, other):
        ''' PolyRange union '''
        bounds = self.bounds + other.bounds
        return PolyRange(*bounds)
    def __add__(self, range):
        ''' PolyRange with new range added '''
        n1 = range[0] ; n2 = n1+len(range)
        bounds = self.bounds + [(n1,n2)]
        return PolyRange(*bounds)
    def __iter__(self):
        self.isEmpty = False
        (self.range_index, self.item_index) = (0,0)
        self.iter = self.ranges[0].__iter__()
        return self
    def next(self):
        # case already emptied
        if self.isEmpty:
            raise StopIteration
        # throw next item
        try:
            item = self.iter.next()
        except StopIteration:
            self.range_index += 1
            self.item_index = 0
        else:
            self.item_index += 1
            return item
        # next range
        if len(self.ranges) > self.range_index:
            self.iter = self.ranges[self.range_index].__iter__()
        else:
            self.empty = True
            raise StopIteration
        # throw item
        try:
            item = self.iter.next()
        except StopIteration:
            self.empty = True
            raise StopIteration
        else:
            self.item_index += 1
            return item
    def __str__(self):
        return "(%s)" %'U'.join("[%s,%s)" %(n1,n2) for (n1,n2) in self.bounds)
    def __repr__(self):
        return "PolyRange(%s)" %', '.join(str(b) for b in self.bounds)
        return False

def testPolyRange():
    print "=== base case -- test in/contains"
    pr = PolyRange((1,3),(5,7),(9,11))
    print "%s\t%s" %(pr,repr(pr))
    print 2 in pr, 4 in pr

    print "=== union"
    pr = PolyRange((1,3),(5,7)) | PolyRange((9,11))
    print pr

    print "=== addition, iteration"
    r = xrange(3,9)
    pr0 = PolyRange((1,3),(5,7))
    pr1 = pr0 + r
    print pr1
    for i in pr1: print i,
testPolyRange()




More information about the Tutor mailing list