1

I want to use a use a name to refer to an index range for array/list indexing. Plus, I want to be able to do arithmetic on it. For instance, I want to do

myrange = 3:10
myrange2 = myrange + 5
arr2[myrange2] = arr1[myrange]  # This being equivalent to arr2[8:15] = arr1[3:10] 
myrange3 = myrange * 2 + 5
arr2[myrange3] = arr1[myrange]  # This being equivalent to arr2[11:25] = arr1[3:10] 

Is this possible with python lists and numpy arrays?

6
  • 1
    Looks difficult as slice is not subclassable stackoverflow.com/a/39971377/7207392. Also using dunders __int__ or __index__ doesn't seem to work. Commented Dec 8, 2019 at 13:49
  • The 'm:n' slice notation only works in an indexing expression. That is, it's a Python syntax feature. The interpreter converts it to a slilce object, and passes that to the __getitem__ method. By itself a slice object is quite simple, with just a couple of attributes. np.s_ and np.r_ are special numpy class instances that help generate and expand slices. Commented Dec 8, 2019 at 17:50
  • @hpaulj - I will try digesting your comment. In the meantime, would you say the answer to my question is Yes or No? (I could not figure this out from the comment, yet). Commented Dec 9, 2019 at 5:13
  • No, you cannot make the Python interpreter evaluate myrange = 3:10. That's an invalid syntax error. Commented Dec 9, 2019 at 5:18
  • @hpaulj - Please see the approach in the answers... they seem to show that it is possible (by not using strictly the notation 3:10, but being able to name a slice)... Commented Dec 9, 2019 at 5:24

2 Answers 2

2

You can simply use a slice():

myrange = slice(3, 10)
myrange2 = slice(3 + 5, 10 + 5)
arr2[myrange2] = arr1[myrange]

This can be made into a function easily:

def add_to_slice(slice_, offset):
    return slice(slice_.start + offset, slice_.stop + offset)


myrange = slice(3, 10)
myrange2 = add_to_slice(myrange, 5)
arr2[myrange2] = arr1[myrange]

If you want to use + you would need to patch the slice class (since slice is not an acceptable base class) to include a __add__ method, i.e.:

class Slice(slice):
    pass

TypeError: type 'slice' is not an acceptable base type


EDIT

A "perhaps close enough" approach would be wrap a slice around another class, say Slice and, optionally, make it easy to access the inner slice, e.g.:

class Slice(object):
    def __init__(self, *args):
        self.slice_ = slice(*args)

    def __call__(self):
        return self.slice_

    def __add__(self, offset):
        return Slice(self.slice_.start + offset, self.slice_.stop + offset, self.slice_.step)


myrange = Slice(2, 5)
myrange2 = myrange + 3

mylist = list(range(100))
print(mylist[myrange()])
print(mylist[myrange2()])

(You may want to refine the code for production to handle the possibility of the attributes of slice being None).

Sign up to request clarification or add additional context in comments.

2 Comments

Very interesting approach. I will try this out. I meant to be able to do other arithmetic operations as well, and even compound operations (e.g., slice * 2 + 4). With this approach, it seems to me that is also straightforward, by defining __multiply__, etc. Would you think so?
@sancho.sReinstateMonica Yes, you can peek the operator module to see what to implement (e.g. * operator is __mul__, etc.). Note that you could also accept a str in the constructor with the colon syntax, which would allow you to write Slice('1:10') in place of Slice(1, 10), although that may be useful for handling user input than to simplify syntax in the code.
1

You can use slice

a = slice(1,3)
'hello'[a] -> ell

You can access the attributes with a.start/a.stop/a.step. The attributes are read only but you can create a new slice from them for the arithmetic requirement

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.