code: def _get_index_range(start, stop, length, step=1):
      
      if step == 0:
          raise ValueError('step size cannot be zero')
      if length < 0:
          raise ValueError('array length cannot be less than zero')
      if step is None:
          step = 1
      if start is None:
          if step > 0:
              start = 0
          else:
              start = length - 1
      elif start < 0:
          start += length
          if start < 0:
              raise IndexError('Slicing start %d exceeds limit of %d' % (start-length, length))
      elif start >= length:
          raise IndexError('Slicing start %d exceeds limit of %d' % (start, length))
  
      if stop is None:
          if step > 0:
              stop = length
          else:
              # this supports case such as ::-1
              # stop = -1 here refers to the element before index 0,
              # instead of the last element in the array
              stop = -1
      elif stop < 0:
          stop += length
          if stop < 0:
              raise IndexError('Slicing stop %d exceeds limit of %d' % (stop-length, length))
      elif stop > length:
          raise IndexError('Slicing stop %d exceeds limit of %d' % (stop, length))
  
      return start, stop, step
docs: Given start, stop, step and array length, return
      absolute values of start, stop, and step for generating index range.
      The returned values have been compensated by adding length if they
      are less than zero for all the cases but slice(None, None, -1).
      Note that the returned value of stop is not necessarily >= 0, since
      absolute stop is -1 in the case of slice(None, None, -1).