I'm using Python 3.3. I want to get a slice
object and use it to make a new range
object.
It goes something like that:
>>> class A:
def __getitem__(self, item):
if isinstance(item, slice):
return list(range(item.start, item.stop, item.step))
>>> a = A()
>>> a[1:5:2] # works fine
[1, 3]
>>> a[1:5] # won't work :(
Traceback (most recent call last):
File "<pyshell#18>", line 1, in <module>
a[1:5] # won't work :(
File "<pyshell#9>", line 4, in __getitem__
return list(range(item.start, item.stop, item.step))
TypeError: 'NoneType' object cannot be interpreted as an integer
Well, the problem is obvious here - range
doesn't accept None
as a value:
>>> range(1, 5, None)
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
range(1, 5, None)
TypeError: 'NoneType' object cannot be interpreted as an integer
But what is not obvious (to me) is the solution. How will I call range
so it will work in every case?
I'm searching for a nice pythonic way to do it.
Try
def ifnone(a, b):
return b if a is None else a
class A:
def __getitem__(self, item):
if isinstance(item, slice):
if item.stop is None:
# do something with itertools.count()
else:
return list(range(ifnone(item.start, 0), item.stop, ifnone(item.step, 1)))
else:
return item
This will reinterpret .start
and .step
appropriately if they are None
.
Another option could be the .indices()
method of a slice. It is called with the number of entries and reinterprets None
to the appropriate values and wraps negative values around the given length parameter:
>>> a = slice(None, None, None)
>>> a.indices(1)
(0, 1, 1)
>>> a.indices(10)
(0, 10, 1)
>>> a = slice(None, -5, None)
>>> a.indices(100)
(0, 95, 1)
It depends what you intend to do with negative indices …
Edit 2024:
The easiest way is probably
class A:
def __init__(self, length):
self._length = length
def __len__(self):
return self._length
def __getitem__(self, item):
if isinstance(item, slice):
return range(*item.indices(self._length))
else:
return item
Here you have to provide a length when creating A()
which is then used if the slicing needs it.