Ellipsis lists […] and concatenating a list to itself [duplicate]

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.

Leave a Comment