21

In Python, is it possible to encapsulate exactly the common slice syntax and pass it around? I know that I can use slice or __slice__ to emulate slicing. But I want to pass the exact same syntax that I would put in the square brackets that would get used with __getitem__.

For example, suppose I wrote a function to return some slice of a list.

def get_important_values(some_list, some_condition, slice):
    elems = list(filter(some_condition, some_list))
    return elems[slice]

This works fine if I manually pass in a slice object:

In [233]: get_important_values([1,2,3,4], lambda x: (x%2) == 0, slice(0, None))
Out[233]: [2, 4]

But what I want to let the user pass is exactly the same slicing they would have used with __getitem__:

get_important_values([1,2,3,4], lambda x: (x%2) == 0, (0:-1) )

# or

get_important_values([1,2,3,4], lambda x: (x%2) == 0, (0:) )

Obviously this generates a syntax error. But is there any way to make this work, without writing my own mini parser for the x:y:t type slices, and forcing the user to pass them as strings?

Motivation

I could just make this example function return something directly sliceable, such as filter(some_condition, some_list), which will be the whole result as a list. In my actual example, however, the internal function is much more complicated, and if I know the slice that the user wants ahead of time, I can greatly simplify the calculation. But I want the user to not have to do much extra to tell me the slice ahead of time.

5
  • 1
    Where you wrote __getattr__ I assume you mean __getitem__. Commented Dec 4, 2012 at 15:32
  • Yes, sorry. I'll edit to fix it above. Commented Dec 4, 2012 at 15:33
  • 1
    It would be kind of cool if Python had such a thing as "slice literals". I don't imagine it would be too hard to hack into the language but I imagine such a suggestion would be rejected as mostly unnecessary. Commented Dec 4, 2012 at 15:44
  • 1
    For numpy users, there is one more answer here using numpy.s_. Commented Mar 1, 2013 at 16:58
  • Is there a rejected PEP for this? I swear there was, but I can't find it now. Commented Oct 7, 2014 at 16:05

3 Answers 3

16

Perhaps something along the following lines would work for you:

class SliceMaker(object):
  def __getitem__(self, item):
    return item

make_slice = SliceMaker()

print make_slice[3]
print make_slice[0:]
print make_slice[:-1]
print make_slice[1:10:2,...]

The idea is that you use make_slice[] instead of manually creating instances of slice. By doing this you'll be able to use the familiar square brackets syntax in all its glory.

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

2 Comments

This is a great idea. It's a lot cleaner than passing around the individual bounds of the slice. If I have to slightly burden the users of this with making their own slice input, I think this is the least intrusive of the suggestions so far.
Note that NumPy has this built in as np.s_: docs.scipy.org/doc/numpy/reference/generated/numpy.s_.html
2

In short, no. That syntax is only valid in the context of the [] operator. I might suggest accepting a tuple as input and then pass that tuple to slice(). Alternatively, maybe you could redesign whatever you're doing so that get_important_values() is somehow implemented as a sliceable object.

For example, you could do something like:

class ImportantValueGetter(object):
    def __init__(self, some_list, some_condition):
        self.some_list = some_list
        self.some_condition = some_condition

    def __getitem__(self, key):
        # Here key could be an int or a slice; you can do some type checking if necessary
        return filter(self.some_condition, self.some_list)[key]

You can probably do one better by turning this into a Container ABC of some sort but that's the general idea.

4 Comments

How can I emulate the context of []? Also, a tuple could work. But I don't like the need to distinguish between using None to imply (get everything) versus just leaving out that option. If slice took keywords, it might make it better.
Also, if I just wanted get_important_values to be directly sliceable, I would just return filter(some_condition, some_list) directly, which will be the whole result as a list. In my actual example, the internal function is much more complicated, and if I know the slice that the user wants ahead of time, I can greatly simplify the calculation. But I want the user to not have to do much extra to tell me the slice ahead of time.
You could still do that with this example. In __getitem__ if key is a slice (use isinstance(key, slice) then you can access all the start, stop, and step attributes of the slice object and manipulate them/optimize on them at will before applying it directly to the filter result.
I agree with you that I could do it this way, and this is a useful motif to keep in mind for other situations where this design fits a little better.
1

One way (for simple slices) would be to have the slice argument either be a dict or an int,

ie

get_important_values([1, 2, 3, 4], lambda x: (x%2) == 0, {0: -1})

or

get_important_values([1, 2, 3, 4], lambda x: (x%2) == 0, 1)

then the syntax would stay more or less the same.

This wouldn't work though, for when you want to do things like

some_list[0:6:10..]

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.