Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Turn slice into range

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.

like image 682
slallum Avatar asked Dec 13 '12 07:12

slallum


People also ask

Can a range () be sliced Python?

range() v slice() But one is iterable and the other is not. One can be used as a list indices, one cannot. They both conform to the start , stop , step interface. You can slice a range but you can't range a slice.

What is a range slice function in string?

The slice() method returns a portion of an iterable as an object of the slice class based on the specified range. It can be used with string, list, tuple, set, bytes, or range objects or custom class object that implements sequence methods __getitem__() and __len__() methods.

What is the difference between slicing and range in Python?

List slicing uses [:] and Range uses (,) One is using Square Brackets with colon, One is using Brackets with comma. Can anyone help me to understand the two, and what should I be aware of when I deal with these type? Maybe an example? thank you so much!


2 Answers

There's an easier way to do this (at least in 3.4, I don't have 3.3 at the moment, and I don't see it in the changelog).

Assuming your class already has a known length you can just slice a range of that size:

>>> range(10)[1:5:2] range(1, 5, 2) >>> list(range(10)[1:5:2]) [1, 3] 

If you don't know the length a priori you'll have to do:

>>> class A:     def __getitem__(self, item):         if isinstance(item, slice):             return list(range(item.stop)[item]) >>> a = A() >>> a[1:5:2] [1, 3] >>> a[1:5] [1, 2, 3, 4] 
like image 106
CrazyCasta Avatar answered Sep 20 '22 10:09

CrazyCasta


Try

class A:     def __getitem__(self, item):         ifnone = lambda a, b: b if a is None else a         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...

like image 25
glglgl Avatar answered Sep 20 '22 10:09

glglgl