getitem

Slices, Ranges and __getitem__()

One annoyance when implementing __getitem__() is debugging the slice syntax interactively .. Below you can see an example.

First you create a dummy class with simple method that print its arguments.

Then you can experiment.

class Blah: 
  def __getitem__(self,*args): 
    print(args) 
    return args

b = Blah()
b[1]
b[2:5]
b[::2,2:11:2]

s = b[::3]

print()

#filling the indices
ind = s[0].indices(12)
print(f'indices: {s[0]} => {ind}')

#make it a range
rng = range(*s[0].indices(12))
print(f'range: {rng}')

for i in rng: print(i)
(1,)
(slice(2, 5, None),)
((slice(None, None, 2), slice(2, 11, 2)),)
(slice(None, None, 3),)

indecies: slice(None, None, 3) => (0, 12, 3)
range: range(0, 12, 3)
0
3
6
9

In addition inside your method you can convert a slice to a range by using the .indices() method … and then use them to do processing in a loop.

Slice to Range

Sometimes inside __getitem__() method you may need to convert the “slice” coming as argument to a “range” :

#convert slice to range
def slice2range(s):	
	start = 0 if s.start is None else s.start
	step = 1 if s.step is None else s.step
	end = step if s.stop is None else s.stop
	return range(start,end,step)

#inside your code it will be something like this :
def __getitem__(self, item):
        if isinstance(item, slice):
        ....

Example :

: slice2range(slice(2,5))                                                                                                                                            
: range(2, 5)

: slice2range(slice(2,5,1))                                                                                                                                          
: range(2, 5)

: slice2range(slice(5))                                                                                                                                              
: range(0, 5)