838

While idly surfing the namespace I noticed an odd looking object called Ellipsis, it does not seem to be or do anything special, but it's a globally available builtin.

After a search I found that it is used in some obscure variant of the slicing syntax by Numpy and Scipy... but almost nothing else.

Was this object added to the language specifically to support Numpy + Scipy? Does Ellipsis have any generic meaning or use at all?

D:\workspace\numpy>python
Python 2.4.4 (#71, Oct 18 2006, 08:34:43) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> Ellipsis
Ellipsis
martineau
  • 119,623
  • 25
  • 170
  • 301
Salim Fadhley
  • 22,020
  • 23
  • 75
  • 102
  • 3
    See the answers to http://stackoverflow.com/questions/752602/slicing-in-python-expressions-documentation – Patrick McElhaney Apr 21 '09 at 12:34
  • 49
    I found it like this: I entered `x=[];x.append(x);print(x)`, to see how it handled stringifying cyclical objects. It returned `[[...]]`. I thought "I wonder what happens if I type in `[[...]]`? My guess was it would throw a syntax error. Instead, it returned `[[Ellipsis]]`. Python is so weird. The Google search that ensued brought me to this page. – Cyoce Jan 09 '16 at 00:38
  • 51
    note that the `...` in a recursive repr is just a placeholder and has no relation to `Ellipsis` – Eevee Jun 20 '16 at 03:15
  • 39
    On a totally side note, triple dot in import means "import from two packages up". – Mad Physicist Aug 23 '16 at 21:59
  • 1
    Awesome James Powell talk https://www.youtube.com/watch?v=65_-6kEAq58 – SARose Feb 01 '19 at 20:45
  • @Matthew D. Scholefield just short remark looks like ellipsis slicing syntax is limited to numpy arrays/matrices, not to python built-in list – wiesiu_p Feb 19 '19 at 09:52
  • @MadPhysicist I'm not sure if that deserves to be an answer to this question, but I'd like to read more about it and am having trouble finding anything. (At the risk of going off on an extreme tangent, I've just run into a ModuleNotFound error in somebody else's project where they use the triple dot for a relative import. The problem in that case was that the module being imported was a cython module and needed to be compiled. It took me ages to rule out an error with the path because I didn't understand the triple dot.) – craq Aug 01 '19 at 00:28
  • @craq. It's one dot per level up. I'll find the official docs if I can. It's definitely in there somewhere. It would be a legitimate question in my opinion, since the docs are hard to find. – Mad Physicist Aug 01 '19 at 00:36
  • 2
    @croq https://stackoverflow.com/q/32395926/2988730. https://stackoverflow.com/q/1054271/2988730. Those two should explain everything, with proper links to docs and PEP in the answers. – Mad Physicist Aug 01 '19 at 00:52
  • As python language reference states: Ellipsis is a type which has a single value. There is a single object with this value. This object is accessed through the literal `...` or the built-in name Ellipsis. Its truth value is true. – Youjun Hu Feb 17 '22 at 02:12

14 Answers14

830

This came up in another question recently. I'll elaborate on my answer from there:

Ellipsis is an object that can appear in slice notation. For example:

myList[1:2, ..., 0]

Its interpretation is purely up to whatever implements the __getitem__ function and sees Ellipsis objects there, but its main (and intended) use is in the numpy third-party library, which adds a multidimensional array type. Since there are more than one dimensions, slicing becomes more complex than just a start and stop index; it is useful to be able to slice in multiple dimensions as well. E.g., given a 4 × 4 array, the top left area would be defined by the slice [:2, :2]:

>>> a
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12],
       [13, 14, 15, 16]])

>>> a[:2, :2]  # top left
array([[1, 2],
       [5, 6]])

Extending this further, Ellipsis is used here to indicate a placeholder for the rest of the array dimensions not specified. Think of it as indicating the full slice [:] for all the dimensions in the gap it is placed, so for a 3d array, a[..., 0] is the same as a[:, :, 0] and for 4d a[:, :, :, 0], similarly, a[0, ..., 0] is a[0, :, :, 0] (with however many colons in the middle make up the full number of dimensions in the array).

Interestingly, in python3, the Ellipsis literal (...) is usable outside the slice syntax, so you can actually write:

>>> ...
Ellipsis

EDIT: Ellipsis is also used in the standard library typing module: e.g. Callable[..., int] to indicate a callable that returns an int without specifying the signature, or tuple[str, ...] to indicate a variable-length homogeneous tuple of strings.

Augustin
  • 2,444
  • 23
  • 24
Brian
  • 116,865
  • 28
  • 107
  • 112
  • 43
    it's also used in PEP484 type hinting in stub files – noɥʇʎԀʎzɐɹƆ Jul 14 '16 at 20:01
  • 27
    FYI, the FastAPI framework (which is for python 3.6+) also (now) uses it. https://fastapi.tiangolo.com/tutorial/query-params-str-validations/ – Andrew Allaire Jul 17 '19 at 18:02
  • 5
    @ArtOfWarfare you're totally right, and this is coming from someone who verbally says "ellipsis" instead of trailing off between sentences. – PrimeRibeyeDeal Oct 02 '19 at 18:15
  • 4
    I found this. It seems to appear when you make a self-reference (circular reference) in a list: `a = [1, 2]; a[0] = a; print(a)` gives `[[...], 2]`. Is this the same thing or a different use? – Bill Jan 26 '20 at 18:20
  • 1
    you also get it when copying large expressions from VSCode. I hadn't realised it was a main obect – hum3 May 13 '20 at 11:41
  • 2
    Just as another reference, you can look at the standard `socket` module and you'll see definitions such as `def recv(self, bufsize: int, flags: int = ...) -> bytes: ...`, where `...` is used for the function's body. I know this is supposed to make a syscall down on the C lib, but I have no idea what the `...` would mean here. – code_dredd Jun 09 '20 at 21:18
  • 3
    It's a "whatever". You know that there's an integer default for the flags and that there's a body, but you don't know what it is because it's OS specific. The actual `socket` is of course implemented in C, which you don't want to add typing info to, it's way too tedious to do that. – Matthias Urlichs Jul 02 '20 at 05:48
  • 1
    Is that ellipsis similar to `a = [1,2,3]` - `a.append(a)` - `print(a)`? one for recursive lists? Or is that just a display gimmic? – Patrick Artner Sep 17 '20 at 11:40
370

In Python 3, you can¹ use the Ellipsis literal ... as a “nop” placeholder for code that hasn't been written yet:

def will_do_something():
    ...

This is not magic; any expression can be used instead of ..., e.g.:

def will_do_something():
    1

(Can't use the word “sanctioned”, but I can say that this use was not outrightly rejected by Guido.)

¹ 'can' not in {'must', 'should'}

tzot
  • 92,761
  • 29
  • 141
  • 204
  • 273
    In a half-convention, I often see ``...`` used where people want to indicate something they intend to fill in later (a 'todo' empty block) and ``pass`` to mean an block intended to have no code. – Gareth Latty Apr 16 '12 at 01:04
  • 42
    Python also has the `NotImplemented` literal, which is useful when you want your incomplete function to return something meaningful (instead of `None` as in your example). (Another usecase: [Implementing arithmetic operations](https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations)) – zvyn Jun 26 '15 at 05:19
  • 27
    @zvyn That is not a literal. It's just a name. For example `NotImplemented = 'something_else'` is valid python, but `... = 'something_else'` is a syntax error. – wim Apr 13 '16 at 17:51
  • 1
    @wim: indeed, and I thought Python 3 finally got rid of those builtin names which aren't litterals or callables. – zvyn Apr 14 '16 at 01:42
  • @Schilcote: Exceptions are callable and wether they should be builtin or in a separate module is debatable. – zvyn Jun 06 '16 at 22:10
  • 5
    @zvyn What if an exception occurred while importing that module? :) – pizzapants184 Apr 24 '17 at 01:15
  • 15
    @zvyn `NotImplemented` is not intended to be an alternative to `None`. Its usage is rather narrow. See documentation [here](https://docs.python.org/3/library/constants.html) – hans Dec 11 '18 at 10:46
  • 2
    `raise NotImplemented` was a thing in py2 – Jonathan Jan 03 '19 at 19:41
  • 7
    and `raise NotImplementedError` is still a thing in py3 – tzot Jun 23 '20 at 12:32
  • "pass" also works exactly fine if you want a placeholder for a function. – nikhil swami Sep 20 '20 at 03:32
  • `...` can be considered as a substitute for `pass # TODO write code` – tzot Sep 21 '20 at 09:49
  • 3
    You could also use a docstring in this instance - seems like better practice. – naught101 Oct 09 '20 at 01:19
  • fwiw I agree with @naught101 that a docstring is better, because a docstring doesn't count as an unreachable statement - and so, you don't end up with unreachable statements in `abstractmethod` bodies, or unimplemented `pass` or `...` statements affecting test coverage. – jsj Nov 18 '20 at 17:16
  • I've started using this as a placeholder for Jupyter cells-to-fill in homework from lesctures I'm designing. I just accidentally stumbled upon it (as most of us must've) and I can just say... it's such a curious nugget of information! Imma keep it – Julio Cezar Silva Oct 18 '22 at 15:46
130

As of Python 3.5 and PEP484, the literal ellipsis is used to denote certain types to a static type checker when using the typing module.

Example 1:

Arbitrary-length homogeneous tuples can be expressed using one type and ellipsis, for example Tuple[int, ...]

Example 2:

It is possible to declare the return type of a callable without specifying the call signature by substituting a literal ellipsis (three dots) for the list of arguments:

def partial(func: Callable[..., str], *args) -> Callable[..., str]:
    # Body
phoenix
  • 7,988
  • 6
  • 39
  • 45
  • Example 1. What's the difference from `tuple[int]`? – Hello Human Aug 15 '23 at 11:12
  • `tuple[int]` means a `tuple` with exactly one `int` (example: `(1,)`). `tuple[int, ...]` means a `tuple` with 0 or more `int`s, such as: `(1, 2, 3)`. – phoenix Aug 15 '23 at 12:12
  • Ah, OK, tuple is something like a "special case", it seems: https://docs.python.org/3/library/typing.html#annotating-tuples – Hello Human Aug 16 '23 at 13:30
70

Summing up what others have said, as of Python 3, Ellipsis is essentially another singleton constant similar to None, but without a particular intended use. Existing uses include:

  • In slice syntax to represent the full slice in remaining dimensions
  • In type hinting to indicate only part of a type(Callable[..., int] or Tuple[str, ...])
  • In type stub files to indicate there is a default value without specifying it

Possible uses could include:

  • As a default value for places where None is a valid option
  • As the content for a function you haven't implemented yet
Matthew D. Scholefield
  • 2,977
  • 3
  • 31
  • 42
  • "As a default value for places where None is a valid option" yes – Ben Mar 03 '22 at 13:27
  • I wouldn't use `...` as a default value. `None` at least conveys the semantic meaning of "there was no value passed"; `...` doesn't. Alternate sentinels are typically purpose-made instances of `object` or a custom class, meant to be tested against with `is`. See, for example, the [`dataclasses` module](https://github.com/python/cpython/blob/3.10/Lib/dataclasses.py#L174), which defines several custom sentinels in this way. – chepner Mar 15 '22 at 14:11
  • "As a default value for places where None is a valid option" -> are you talking about a type hint or stub file? Could you please elaborate a little more? In normal code, `Ellipsis` is not the same as `None`, as you know. – starriet Mar 30 '22 at 01:23
  • 1
    I think they meant using `...` as the default value for parameters (to indicate that nothing was really passed to that parameter) in functions that also deal with `None` values. `def function(param1 = 5, param2 = ...): if not param2 is Ellipsis: #do something else: #do something else` - This function may have something to do with `None` values being passed in, for instance. Hence we are using `...` or `Ellipsis` here as a default, and it is justified since that object doesn't have an actual use (not for me, atleast) – a_n Jun 02 '22 at 17:04
  • I wrote an ORM utility. `ORM.update(db, obj)` receives an object `obj` to carry the fields and values to update. If one of the fields `obj.x = None`, it means `SET x = null`, and if `obj.x = ...`, it means x is not a field to update. – John Lin Apr 06 '23 at 15:23
49

You can also use the Ellipsis when specifying expected doctest output:

class MyClass(object):
    """Example of a doctest Ellipsis

    >>> thing = MyClass()
    >>> # Match <class '__main__.MyClass'> and <class '%(module).MyClass'>
    >>> type(thing)           # doctest:+ELLIPSIS
    <class '....MyClass'>
    """
    pass
Chiggs
  • 2,824
  • 21
  • 31
  • 16
    But does this actually involve the Ellipsis object? Isn't it just a feature of the doctest parser/matcher? – akaihola Jan 21 '17 at 05:53
  • 3
    @akaihola I'd say that it does, as described at [doctest.ELLIPSIS](https://docs.python.org/2/library/doctest.html#doctest.ELLIPSIS). I expect that most if not all uses of `...` are syntactic, and don't `use` the actual Ellipsis object. Isn't it really nothing more than a handy name for an adaptable concept? – nealmcb Apr 21 '17 at 12:57
  • That's just referring to an ellipsis in the text, not the Python literal `...`. – chepner Mar 15 '22 at 14:12
39

From the Python documentation:

This object is commonly used by slicing (see Slicings). It supports no special operations. There is exactly one ellipsis object, named Ellipsis (a built-in name). type(Ellipsis)() produces the Ellipsis singleton.

It is written as Ellipsis or ....

Simon Lieschke
  • 13,058
  • 6
  • 46
  • 60
30

For anyone coming to this answer from working in a codebase with heavy Pydantic use: this is also how Pydantic indicates a field that is required but can be set to None, which they refer to as "required optional fields". This is why they end up used in FastAPI, too.

tykom
  • 659
  • 5
  • 8
27

__getitem__ minimal ... example in a custom class

When the magic syntax ... gets passed to [] in a custom class, __getitem__() receives a Ellipsis class object.

The class can then do whatever it wants with this Singleton object.

Example:

class C(object):
    def __getitem__(self, k):
        return k

# Single argument is passed directly.
assert C()[0] == 0

# Multiple indices generate a tuple.
assert C()[0, 1] == (0, 1)

# Slice notation generates a slice object.
assert C()[1:2:3] == slice(1, 2, 3)

# Empty slice entries become None.
assert C()[:2:] == slice(None, 2, None)

# Ellipsis notation generates the Ellipsis class object.
# Ellipsis is a singleton, so we can compare with `is`.
assert C()[...] is Ellipsis

# Everything mixed up.
assert C()[1, 2:3:4, ..., 6, :7:, ..., 8] == \
       (1, slice(2,3,4), Ellipsis, 6, slice(None,7,None), Ellipsis, 8)

The Python built-in list class chooses to give it the semantic of a range, and any sane usage of it should too of course.

Personally, I'd just stay away from it in my APIs, and create a separate, more explicit method instead.

Tested in Python 3.5.2 and 2.7.12.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
14

You can use Ellipsis yourself, in custom slicing situations like numpy has done, but it has no usage in any builtin class.

I don't know if it was added specifically for use in numpy, but I certainly haven't seen it used elsewhere.

See also: How do you use the ellipsis slicing syntax in Python?

Community
  • 1
  • 1
sykora
  • 96,888
  • 11
  • 64
  • 71
13

As mentioned by @noɥʇʎԀʎzɐɹƆ and @phoenix - You can indeed use it in stub files. e.g.

class Foo:
    bar: Any = ...
    def __init__(self, name: str=...) -> None: ...

More information and examples of how to use this ellipsis can be discovered here https://www.python.org/dev/peps/pep-0484/#stub-files

Markus Meskanen
  • 19,939
  • 18
  • 80
  • 119
henryJack
  • 4,220
  • 2
  • 20
  • 24
  • 2
    Ok, and then what happens when I actually instantiate that class and the ellipsis code runs? – Robert Oct 20 '20 at 17:57
  • 1
    @Robert Nothing happens. Think of if as `None`. – 157 239n Jun 23 '21 at 00:13
  • 1
    @Robert The stub file e.g. `module.pyi` exists for static type checking, it is not executable code. It is used to add type information to modules which do not have it. In this usage `def foo(bar:str=...)->str` it indicates there is a default value (i.e. the argument is optional) without indicating what the default is. – Ben Mar 03 '22 at 13:31
  • @Ben simple but clear explanation :) Btw, what are `bar: Any = ...` and `-> None: ...` in the code above? Oh, I think the `...` after `-> None:` just indicates the body of the method maybe? – starriet Mar 28 '22 at 01:51
  • 1
    @starriet `bar: Any = ...` means `Foo` has a member called `bar` of type `Any`, with an unspecified default value. pyi files conventionally do this. – Ben Mar 29 '22 at 13:16
  • @Ben Thanks! Then, just `bar: Any` does *not* insist on `Foo` that it has to have a member called `bar`? Or, does it mean that `bar` must exist but can also be `None`, including any other types? – starriet Mar 29 '22 at 23:44
  • @starriet I don't know, sorry. – Ben Mar 30 '22 at 16:53
5

This is equivalent.

l=[..., 1,2,3]
l=[Ellipsis, 1,2,3]

... is a constant defined inside built-in constants.

Ellipsis

The same as the ellipsis literal “...”. Special value used mostly in conjunction with extended slicing syntax for user-defined container data types.

Community
  • 1
  • 1
prosti
  • 42,291
  • 14
  • 186
  • 151
2

Its intended use shouldn't be only for these 3rd party modules. It isn't mentioned properly in the Python documentation (or maybe I just couldn't find that) but the ellipsis ... is actually used in CPython in at least one place.

It is used for representing infinite data structures in Python. I came upon this notation while playing around with lists.

See this question for more info.

Community
  • 1
  • 1
Aseem Bansal
  • 6,722
  • 13
  • 46
  • 84
  • 13
    Different things.This question asks about the `ellipsis` built-in type and the `Ellipsis` object. Representing infinite data structures with ellipses is purely for display, having nothing to do with `ellipsis` type or `Ellipsis` object. – chys Feb 27 '14 at 06:34
  • 4
    @chys Actually, it does in a small way - Python `__repr__` strings aim to be valid Python expressions - if it wasn't for ellipsis existing in the language as it does, the representation wouldn't be a valid expression. – Gareth Latty Aug 01 '14 at 15:44
  • 4
    @Lattyware Well, it's true the original design so intends. It also intends `eval(repr(a))` aim to be equal to `a`. Unfortunately it's false from time to time in practice, even for built-in types. Try this out: `a=[]; a.append(a); eval(repr(a))`. `repr(a)` is `[[...]]`, invalid expression in Python 2. (In Python 3 it's valid, but the eval result is something different, still contrary to the original intention.) – chys Aug 04 '14 at 05:07
2

In typer ... is used to create required parameters: The Argument class expects a default value, and if you pass the ... it will complain if the user does not pass the particular argument.

You could use None for the same if Ellipsis was not there, but this would remove the opportunity to express that None is the default value, in case that made any sense in your program.

user4344
  • 193
  • 1
  • 10
2

FastAPI makes use of the Ellipsis for creating required Parameters. https://fastapi.tiangolo.com/tutorial/query-params-str-validations/