1

I am new to oop in python.
Below is a class for a mathod that is similar to range() except that it is inclusive for the range boundary.

I am trying to create an indexing method inside the class so that when a specific index is called the element with that index is returned. I read that __getitem__ can perform indexing yet I have not been successful in implementing it correctly. If there is a more efficient way not necessarily using __getitem__ please advise.

Please take a look at the code below, this is a simple code aimed at learning how create classes.

the method starting at def __getitem__(self,index) is the one that does not work and this corresponds to calling the index at the end o[4] which is what I would like to achieve.

class inclusive_range:
    def __init__(self, *args):
        numargs = len(args)
        if numargs < 1: raise TypeError('requires at least one argument')
        elif numargs == 1:
            self.stop = args[0]
            self.start = 0
            self.step = 1
        elif numargs == 2:
            (self.start,self.stop) = args
            self.step = 1
        elif numargs == 3:
            (self.start,self.stop,self.step) = args
        else:
            raise TypeError('three arguments required at most, got {}'.format(numargs))

    def __iter__(self):     # this makes the function (the method) and iterable function
        i = self.start  
        while i <= self.stop:
            yield i
            i += self.step

    def __getitem__(self,index):
        return self[index]
        print(self[index])

def main():
    o = inclusive_range(5, 10, 1)
    for i in o: print(i, end=' ')
    o[2]

if __name__ == "__main__": main()

Thank you

hussam
  • 653
  • 6
  • 13

1 Answers1

4

You can just calculate the number based on self.start, the index and the step size. For your object to be a proper sequence you also need a length, which comes in handy when testing for the boundaries:

def __len__(self):
    start, stop, step = self.start, self.stop, self.step
    if step < 0:
        lo, hi = stop, start
    else:
        lo, hi = start, stop
    return ((hi - lo) // abs(step)) + 1

def __getitem__(self, i):
    length = len(self)
    if i < 0:
        i += length
    if 0 <= i < length:
        return self.start + i * self.step
    raise IndexError('Index out of range: {}'.format(i))

The above is based on my own translation of the range() source code to Python, with a small adjustment to account for the end being inclusive.

I'd cache the __len__ result in __init__, to avoid having to re-calculate it each time you want to know the length.

Ben
  • 9,591
  • 9
  • 32
  • 40
Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997