How to define the getitem class to handle both plain indexes and slicing?
Slice objects gets automatically created when you use a colon in the subscript notation - and that is what is passed to __getitem__. Use isinstance to check if you have a slice object:
from __future__ import print_function class Sliceable(object): def __getitem__(self, subscript): if isinstance(subscript, slice): # do your handling for a slice object: print(subscript.start, subscript.stop, subscript.step) else: # Do your handling for a plain index print(subscript)
Say we were using a range object, but we want slices to return lists instead of new range objects (as it does):
>>> range(1,100, 4)[::-1] range(97, -3, -4)
We can't subclass range because of internal limitations, but we can delegate to it:
class Range: """like builtin range, but when sliced gives a list""" __slots__ = "_range" def __init__(self, *args): self._range = range(*args) # takes no keyword arguments. def __getattr__(self, name): return getattr(self._range, name) def __getitem__(self, subscript): result = self._range.__getitem__(subscript) if isinstance(subscript, slice): return list(result) else: return result r = Range(100)
We don't have a perfectly replaceable Range object, but it's fairly close:
>>> r[1:3] [1, 2] >>> r[1] 1 >>> 2 in r True >>> r.count(3) 1
To better understand the slice notation, here's example usage of Sliceable:
>>> sliceme = Sliceable() >>> sliceme[1] 1 >>> sliceme[2] 2 >>> sliceme[:] None None None >>> sliceme[1:] 1 None None >>> sliceme[1:2] 1 2 None >>> sliceme[1:2:3] 1 2 3 >>> sliceme[:2:3] None 2 3 >>> sliceme[::3] None None 3 >>> sliceme[::] None None None >>> sliceme[:] None None None
Python 2, be aware:
In Python 2, there's a deprecated method that you may need to override when subclassing some builtin types.
From the datamodel documentation:
object.__getslice__(self, i, j)
Deprecated since version 2.0: Support slice objects as parameters to the __getitem__() method. (However, built-in types in CPython currently still implement __getslice__(). Therefore, you have to override it in derived classes when implementing slicing.)
This is gone in Python 3.