What Do Ellipsis [...] Mean in a List

What do ellipsis [...] mean in a list?

It means that you created an infinite list nested inside itself, which can not be printed. p contains p which contains p ... and so on. The [...] notation is a way to let you know this, and to inform that it can't be represented! Take a look at @6502's answer to see a nice picture showing what's happening.

Now, regarding the three new items after your edit:

  • This answer seems to cover it
  • Ignacio's link describes some possible uses
  • This is more a topic of data structure design than programming languages, so it's unlikely that any reference is found in Python's official documentation

What does [...] (an ellipsis) in a list mean in Python?

It is a recursive reference. Your list contains itself, or at least there is some kind of cycle.

Example:

x = []
x.insert(0, x)
# now the repr(x) is '[[...]]'.

The built-in repr for lists detects this situation and does not attempt to recurse on the sub-list (as it normally would), because that would lead to infinite recursion.

Note that ... doesn't necessarily tell you which list is referred to:

y, z = [], []
x = [y, z]
y.insert(0, z)
z.insert(0, y)
# looks the same as it would if y contained y and z contained z.

so repr is not really a complete serialization format for lists.

As to why you're getting them: we're not psychic, and can't fix the problem with your code unless we see the code.

What does the Ellipsis object do?

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.

What does `{...}` mean in the print output of a python variable?

It's an indication that the dict recurses, i.e. contains itself. A much simpler example:

>>> a = []
>>> a.append(a)
>>> a
[[...]]

This is a list whose only element is itself. Obviously the repr can't be printed literally, or it would be infinitely long; instead, the builtin types notice when this has happened and use ... to indicate self-containment.

So it's not a special type of value, just the normal English use of "..." to mean "something was omitted here", plus braces to indicate the omitted part is a dict. You may also see it with brackets for a list, as shown above, or occasionally with parentheses for a tuple:

>>> b = [],
>>> b[0].append(b)
>>> b
([(...)],)

Python 3 provides some tools so you can do this with your own objects, in the form of reprlib.

R: why providing a list to ellipsis (...) when ellipsis is the last argument does not work?

The way arguments work in R is that when you don't name your first argument, R just assumes that goes into the first argument for the function. This is true for the second, third and so forth arguments in the argument list EXCEPT for arguments that come after the ... - because R doesn't know how many arguments you intend to fit into the ..., if you want to change the default of whatever comes after it, you have to name it.

So in your case, when you call function f(), the object list(a=2) goes into the .... But in g(), that same object goes into a. The only way you can get something into ... when that is placed at the end of the argument list without including arguements for a and b is to name it something that isn't a or b, e.g. g(c=list(a=1)).

Ellipsis lists [...] and concatenating a list to itself

Edit: (to address the additional issues raised by your edits to the question):

a = a + b and a += b are not the same operation. The former executes a.__add__(b), the latter executes a.__iadd__(b) ("in-place add").

The difference between the two is that the former always creates a new object (and rebinds the name a to that new object) while the latter modifies the object in-place (if it can, and with a list, it can).

To illustrate this, just look at the addresses of your objects:

>>> a = [1, 2]
>>> id(a)
34660104
>>> a = a + [a]
>>> id(a)
34657224
>>> id(a[2])
34660104

The "new" a was constructed from scratch, first taking the values from the old list a, then concatenating the reference to the old object to it.

Contrast this to:

>>> a = [1, 2]
>>> id(a)
34658632
>>> a += [a]
>>> id(a)
34658632
>>> id(a[2])
34658632

(Old answer, explaining cyclic references):

Consider this:

>>> a = [1, 2]; a += a
>>> a
[1, 2, 1, 2]
>>> a = [1, 2]; a.extend(a)
>>> a
[1, 2, 1, 2]
>>> a = [1, 2]; a += [a]
>>> a
[1, 2, [...]]
>>> a = [1, 2]; a.append(a)
>>> a
[1, 2, [...]]

So, to summarize the first part:

For lists, a += a is equivalent to calling a.extend(a) which modifies a in-place, adding copies of the elements found in a at the start of this operation.

Conversely, a += [a] corresponds to a.append(a), both of which create a reference to the list a (i. e. a pointer to its address in memory) and add that to the list. Which constitutes a so-called "cyclic reference".

If you were to look at the internal representation of a at that point, it would look something like this:

a:    Reference to a list object at address 0xDEADBEEF
a[0]: Reference to the integer object "1"
a[1]: Reference to the integer object "2"
a[2]: Reference to the same list object at address 0xDEADBEEF

Old Python versions (pre-1.5.1) were not smart enough to detect that, so if you were to do a print a, you'd get [1, 2, [1, 2, [1, 2, [1, 2, [1, 2, [1, 2, ... etc. in an infinite loop. Since Python 1.5.1, the interpreter detects this, printing [1, 2, [...]] instead.

what does ellipsis mean in a Matlab function's argument list?

http://www.mathworks.com/help/matlab/matlab_prog/continue-long-statements-on-multiple-lines.html

Continue Long Statements on Multiple Lines

This example shows how to continue a statement to the next line using ellipsis (...).

s = 1 - 1/2 + 1/3 - 1/4 + 1/5 ...
- 1/6 + 1/7 - 1/8 + 1/9;

How do you use the ellipsis slicing syntax in Python?

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.



Related Topics



Leave a reply



Submit