How do you use the ellipsis slicing syntax in Python?
Asked Answered
T

4

210

This came up in Hidden features of Python, but I can't see good documentation or examples that explain how the feature works.

Trawick answered 23/9, 2008 at 0:17 Comment(0)
M
134

Ellipsis, or ... is not a hidden feature, it's just a constant. It's quite different to, say, javascript ES6 where it's a part of the language syntax. No builtin class or Python language constuct makes use of it.

So the syntax for it depends entirely on you, or someone else, having written code to understand it.

Numpy uses it, as stated in the documentation. Some examples here.

In your own class, you'd use it like this:

>>> class TestEllipsis(object):
...     def __getitem__(self, item):
...         if item is Ellipsis:
...             return "Returning all items"
...         else:
...             return "return %r items" % item
... 
>>> x = TestEllipsis()
>>> print x[2]
return 2 items
>>> print x[...]
Returning all items

Of course, there is the python documentation, and language reference. But those aren't very helpful.

Metrology answered 23/9, 2008 at 0:24 Comment(3)
looks quite broken since the "propper" way to say all items is >>> x[:] >>> x[:, 1:2]Sheff
@Ronny: The point was to demonstrate some custom usage of Ellipsis.Metrology
The links appear to be broken.Balneal
S
308

The ellipsis is used in numpy to slice higher-dimensional data structures.

It's designed to mean at this point, insert as many full slices (:) to extend the multi-dimensional slice to all dimensions.

Example:

>>> from numpy import arange
>>> a = arange(16).reshape(2,2,2,2)

Now, you have a 4-dimensional matrix of order 2x2x2x2. To select all first elements in the 4th dimension, you can use the ellipsis notation

>>> a[..., 0].flatten()
array([ 0,  2,  4,  6,  8, 10, 12, 14])

which is equivalent to

>>> a[:,:,:,0].flatten()
array([ 0,  2,  4,  6,  8, 10, 12, 14])

In your own implementations, you're free to ignore the contract mentioned above and use it for whatever you see fit.

Sanfordsanfourd answered 23/9, 2008 at 0:55 Comment(6)
Maybe I am wrong but isn't it that a[:,:,:,0] will return a copy and a[...,0] will return the "view" and not the copy? I tried running id() against both the versions and for a 3-dim array: a[:,:,:, 0], a[:,:,:, 1], a[:,:,:, 2] all have different ids whereas: a[..., 0], a[..., 1], a[..., 2] all have same ids.Arid
@Arid not on my machine ;) id() returns the same value for both. Also checking with __array_interface__['data'] shows the same memory address.Spunk
I find we can use a[indexes, ...] while a is a 1-dimenstional array even!Navada
what is a 4 dimensional matrix? It makes sense to call it as 4 dimensional array but not as matrix., IMO.Pine
Ellipses are also useful for zero-dimensional data structures. They are the only way I know of to write into scalar numpy.ndarrays, e.g.: my_scalar = np.asarray(3); my_scalar[...] = 5. If you do my_scalar[:] = 5, you'll rightfully get an error, because there's no dimension 0 for the : to iterate over.Relict
@Relict You can also use my_scalar.itemset(scalarvalue). Of course, my_scalar[...]=scalar_value is shorter, but you said in the above comment, that it is the only way you know. Just giving an alternative.Counterirritant
M
134

Ellipsis, or ... is not a hidden feature, it's just a constant. It's quite different to, say, javascript ES6 where it's a part of the language syntax. No builtin class or Python language constuct makes use of it.

So the syntax for it depends entirely on you, or someone else, having written code to understand it.

Numpy uses it, as stated in the documentation. Some examples here.

In your own class, you'd use it like this:

>>> class TestEllipsis(object):
...     def __getitem__(self, item):
...         if item is Ellipsis:
...             return "Returning all items"
...         else:
...             return "return %r items" % item
... 
>>> x = TestEllipsis()
>>> print x[2]
return 2 items
>>> print x[...]
Returning all items

Of course, there is the python documentation, and language reference. But those aren't very helpful.

Metrology answered 23/9, 2008 at 0:24 Comment(3)
looks quite broken since the "propper" way to say all items is >>> x[:] >>> x[:, 1:2]Sheff
@Ronny: The point was to demonstrate some custom usage of Ellipsis.Metrology
The links appear to be broken.Balneal
F
74

This is another use for Ellipsis, which has nothing to do with slices: I often use it in intra-thread communication with queues, as a mark that signals "Done"; it's there, it's an object, it's a singleton, and its name means "lack of", and it's not the overused None (which could be put in a queue as part of normal data flow). YMMV.

Faustofaustus answered 23/9, 2008 at 9:34 Comment(4)
Mightn't it be clearer to just say: "Done = object()" somewhere and just use that?Smack
Not necessarily - it requires you to actually say Done=object() somewhere. Sentinel values aren't necessarily a bad thing -- and using otherwise nearly-useless Python singletons as sentinels isn't so horrible IMO (Ellipsis and () are the ones I've used where None would be confusing).Sevier
Regarding Done = object(), I think using Ellipsis is better, especially if you're using it for communication with queues. If you go from intra-thread to intra-process communication, id(Done) will not be the same in the other process, and there is nothing to distinguish one object from another. The id of Ellipsis won't be the same either, but at least the type will be the same - this is the point of a singleton.Cribriform
The question says "How do you use ellipsis" but I believe you took this the wrong way. It has many interpretations. But I think the correct on is: "How is Ellipsis used?" ie "What steps should I take to make use of Ellipsis in my own code.".Unstressed
D
15

As stated in other answers, it can be used for creating slices. Useful when you do not want to write many full slices notations (:), or when you are just not sure on what is dimensionality of the array being manipulated.

What I thought important to highlight, and that was missing on the other answers, is that it can be used even when there is no more dimensions to be filled.

Example:

>>> from numpy import arange
>>> a = arange(4).reshape(2,2)

This will result in error:

>>> a[:,0,:]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: too many indices for array

This will work:

a[...,0,:]
array([0, 1])
Decarlo answered 7/6, 2018 at 4:3 Comment(1)
"this will work", sure, but we're interested in the reason it works. Perhaps because Numpy interprets ... as "add the correct number of :, required to create a valid index given the array shape". In your example it adds nothing, for a 3D array it would add :,, for a 4D array it would add :, :,, etc. This interpretation is the one of Numpy, but another package, or another developer may interpret ... in an entirely different way, provided they explain how to use it.Richter

© 2022 - 2024 — McMap. All rights reserved.