8

The following is the slicings syntax that I copied from The Python Language Reference:

slicing      ::=  primary "[" slice_list "]"
slice_list   ::=  slice_item ("," slice_item)* [","]
slice_item   ::=  expression | proper_slice
proper_slice ::=  [lower_bound] ":" [upper_bound] [ ":" [stride] ]
lower_bound  ::=  expression
upper_bound  ::=  expression
stride       ::=  expression

Per my understanding, this syntax equates to SomeMappingObj[slice_item,slice_item etc...] which again equates to something like a[0:2:1,4:7:1] and a =[i for i in range(20)].

But, I can't test this in IPython and I did not find any questions about multiple slicings. Is my interpretation about multiple slicing in python correct? What am I doing incorrectly?

In [442]: a=[i for i in range(20)]

In [443]: a[0:12:2]
Out[443]: [0, 2, 4, 6, 8, 10]

In [444]: a[0:12:2,14:17:1]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-444-117395d33bfd> in <module>()
----> 1 a[0:12:2,14:17:1]

TypeError: list indices must be integers or slices, not tuple
4
  • what are you expecting as an output for a[0:12:2,14:17:1]? Commented Sep 20, 2016 at 18:03
  • 1
    That is what I wanted to find out. From the syntax, it seems to be a valid operation. Common sense would make me guess the result as [0,2,4,6,8,10,14,15,16]. Commented Sep 20, 2016 at 18:05
  • 1
    For your purpose use a[0:12:2] + a[14:17:1] Commented Sep 20, 2016 at 18:06
  • 2
    I have to say, this question is much more insightful than the title initially led me to expect. Nice work. Commented Sep 20, 2016 at 18:09

4 Answers 4

4

Note that the grammar is structured this way to allow two things:

  1. A family of slice literals:

    1. x:y:z == slice(x, y, z)
    2. x:y == slice(x, y, None)
    3. x: == slice(x, None, None)
    4. x::z == slice(x, None, z)
    5. ::z == slice(None, None, z)
    6. :y:z == slice(None, y, z)
    7. :: == slice(None, None, None)
    8. :y: == slice(None, y, None)

    There are a few other patterns possible (x:y:, :y, etc), but each is a variation on one of the above.

  2. Slice literals may only be used inside [...], not in any arbitrary expression.

Otherwise, the comma-separate list is treated like any other tuple. When you write an expression like f[1, 2:3, 5::7], then f.__getitem__ receives a tuple (1, slice(2, 3, None), slice(5, None, 7) as its argument. What f.__getitem__ does with that argument is entirely up to type(f)'s implementation of __getitem__. For instance, lists and strings only accept int and slice values as arguments, and dicts only accept hashable values.

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

Comments

3

A slice_list should contain as many "dimensions" as the object being indexed. The multi-dimensional capability is not used by any Python library object that I am aware of, but you can test it easily with numpy:

import numpy as np
a = np.array([[1, 2], [3, 4]])
a[0:1, 0]

There are a number of such features in the Python language that are not used directly in the main library. The __matmul__ magic method (@ operator) is another example.

2 Comments

I would not say that the slice_list has anything to do with "dimensionality". Rather, it has to do with how many arguments __getitem__ accepts (see the answer from @chepner). You could have a subtype of list which accepts any number of slices, and creates a resulting list containing all the values indexed by every value in each slice_item.
@AisteruFirë. Partially agreed, hence the "scare quotes" around dimensions. I used that term loosely, since arrays are the place I see multiple slices used most commonly. That being said, __getitem__ technically only accepts one argument. It's the implementation's job to check if that item is a tuple or something else.
2

This isn't a syntax issue hence no SyntaxError, this syntax is totally supported. list's just don't know what to do with your slices. Take for example a dummy class that does nothing but define __getitem__ that receives the contents of subscriptions []:

class DummySub:
    def __getitem__(self, arg):
        print(arg)

f = DummySub()

It just prints its arg. We can supply slices, as permitted by the grammar, but, it's up to the implementing object to decide if these are an operation that's supported and act on them (like nparrays do) or not (and raise a TypeError):

f[1:2:3, 4:4:4]
(slice(1, 2, 3), slice(4, 4, 4))

Heck:

f[1:2:3, 4:5:6, 7:8:9, ...]  # totally valid
(slice(1, 2, 3), slice(4, 5, 6), slice(7, 8, 9), Ellipsis)

By reading further on in the reference for slicings you should see that:

The semantics for a slicing are as follows. The primary is indexed (using the same __getitem__() method as normal subscription) with a key that is constructed from the slice list, as follows. If the slice list contains at least one comma, the key is a tuple containing the conversion of the slice items; otherwise, the conversion of the lone slice item is the key.

(emphasis mine)

Comments

1

That's valid syntax, so you didn't get a SyntaxError. It's just not a meaningful or supported operation on Python lists. Similarly, "5" + fish isn't a SyntaxError, 1/0 isn't a SyntaxError, and I.am.a.monkey isn't a SyntaxError.

You can't just expect all syntactically valid expressions to be meaningful.

4 Comments

Might be 'not supported operation' but I question 'not a meaningful operation' part. If I want to extract the slice [0,2,4,6,8,10,14,15,16] from a, the easiest and most obvious way is to have multiple slices. I am not sure if something not supported would make it to the language syntax specification. Can you please provide any reference?
@sudheernalubolu: You're assuming that comma-separated slices mean something completely different from what they actually mean. As vishes_shell said in the comments, you want a[0:12:2] + a[14:17:1]. Comma-separated slices are for multidimensional objects.
@sudheernalubolu The grammar allowing any primary to be sliced is what allows you to define __getitem__ for any class. The parser first has to allow the expression before you can define the semantics. Extended slice notation simply isn't defined for any builtin type.
(Ignore the last sentence in my comment above; it's just wrong.)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.