Search code examples
pythonrangemodulo

Circular range in Python


How can I implement a circular range object in Python?

e.g.

Let S is a circular space modulo 2^3 (range [0, 2^3)). I want to generate a range object like this:

crange(3, 7, 2 ** 3)  # => a range object [3, 4, 5, 6]
crange(7, 3, 2 ** 3)  # => a range object [7, 0, 1, 2]

I tried this:

def crange(start, stop, modulo):
    if start > stop:
        return range(start, modulo) or range(stop)
    else:
        return range(start, stop)

But I can't input bigint to crange e.g. crange(8, 2, 2 ** 160).

OverflowError: Python int too large to convert to C ssize_t


Solution

  • I implemented crange which I want (in reference to @Ni and @J.F.Sebastian).

    import math
    
    
    class crange:
        def __init__(self, start, stop, step=None, modulo=None):
            if step == 0:
                raise ValueError('crange() arg 3 must not be zero')
    
            if step is None and modulo is None:
                self.start = 0
                self.stop = start
                self.step = 1
                self.modulo = stop
            else:
                self.start = start
                self.stop = stop
                if modulo is None:
                    self.step = 1
                    self.modulo = step
                else:
                    self.step = step
                    self.modulo = modulo
    
        def __iter__(self):
            n = self.start
            if n > self.stop:
                while n < self.modulo:
                    yield n
                    n += 1
                n = 0
            while n < self.stop:
                yield n
                n += 1
    
        def __contains__(self, n):
            if self.start >= self.stop:
                return self.start <= n < self.modulo or 0 <= n < self.stop
            else:
                return self.start <= n < self.stop
    

    I got the following output:

    >>> print(list(crange(start=7, stop=3, modulo=2 ** 4)))
    [7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2]
    >>> print(3 in crange(start=7, stop=3, modulo=2 ** 4))
    False
    >>> print(7 in crange(start=7, stop=3, modulo=2 ** 4))
    True
    >>> print(list(crange(start=3, stop=7, modulo=2 ** 4)))
    [3, 4, 5, 6]
    >>> print(3 in crange(start=3, stop=7, modulo=2 ** 4))
    True
    >>> print(7 in crange(start=3, stop=7, modulo=2 ** 4))
    False