You can use slice objects, which are passed not to __getslice__ but to __getitem__ when using "extended slicing". Then, move the start of the slice to 0, and the stop to len - 1 while keeping track. Then add zeros:
class MyList(list):
def __getitem__(self, item):
if isinstance(item, slice):
s, e = item.start, item.stop
l = len(self) - 1
left = -s if s < 0 else 0
s = max(s, 0)
right = e - l if e > l else 0
e = min(e, l)
return [0]*left + super(MyList, self).__getitem__(slice(s,e,item.step)) + [0]*right
elif item < 0 or item >= len(self):
return 0
else:
return super(MyList, self).__getitem__(item)
The catch is: you have to force your getslice call to send a slice object, which you can do in one of two ways.
>>> a[-2:2:1] # the step = 1 is necessary
[0, 0, 1, 2]
or
>>> a[slice(-2,2)]
[0, 0, 1, 2]
Works on both ends:
>>> a[-2:6:1]
[0, 0, 1, 2, 3, 0, 0, 0]
Original attempt
If __getslice__ was passed the actual arguments given by a[-2:2], then this would work:
class MyList(list):
def __getitem__(self, item):
if item < 0 or item >= len(self):
return 0
return super(MyList, self).__getitem__(item)
def __getslice__(self, s, e):
print "input: ", s, e
l = len(self) - 1
left = -s if s < 0 else 0
s = max(s, 0)
right = e - l if e > l else 0
e = min(e, l)
return [0]*left + super(MyList, self).__getslice__(s,e) + [0]*right
But for some reason, a[-2:2] calls a.__getslice(2,2) with both values positive.
>>> a[-2:2]
input: 2 2