Skip to content Skip to sidebar Skip to footer

Ellipsis Lists [...] And Concatenating A List To Itself

EDIT: I was careless in my original examples. The behaviour occurs not when I add list A to itself, but rather when I add a list containing list A to A itself. Please see the corre

Solution 1:

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 integerobject"1"
a[1]: Reference to the integerobject"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.

Solution 2:

Consider the following:

In [179]: a = [1, 2]

In [180]: a+=a

In [181]: a
Out[181]: [1, 2, 1, 2]

In [182]: a.append(a)

In [183]: a
Out[183]: [1, 2, 1, 2, [...]]

In [184]: a[5]
-----------------------------------------------
IndexError                                Trace
C:\Users\Marcin\Documents\oneclickcos\oneclickc
----> 1 a[5]

IndexError: list index out of range

In [185]: a[4]
Out[185]: [1, 2, 1, 2, [...]]

In [186]: a[3]
Out[186]: 2

In [187]: a[4]
Out[187]: [1, 2, 1, 2, [...]]

In [188]: a
Out[188]: [1, 2, 1, 2, [...]]

In [189]: a[4][3]
Out[189]: 2

In [190]: a[4][4]
Out[190]: [1, 2, 1, 2, [...]]

In [191]: a[4][5]
-----------------------------------------------
IndexError                                Trace
C:\Users\Marcin\Documents\oneclickcos\oneclickc
----> 1 a[4][5]

IndexError: list index out of range

In [192]: a[4][4]
Out[192]: [1, 2, 1, 2, [...]]

In [193]: a = [1, 2]

In [194]: a+=a

In [195]: a
Out[195]: [1, 2, 1, 2]

In [196]: a
Out[196]: [1, 2, 1, 2]

In [197]: a
Out[197]: [1, 2, 1, 2]

In [198]: a.append(a)

In [200]: a
Out[200]: [1, 2, 1, 2, [...]]

In [201]: a.append(a)

In [202]: a
Out[202]: [1, 2, 1, 2, [...], [...]]

In [203]: a[4]
Out[203]: [1, 2, 1, 2, [...], [...]]

In [204]: a[5]
Out[204]: [1, 2, 1, 2, [...], [...]]

In [205]: id(a)
Out[205]: 64692680L

In [206]: id(a[5])
Out[206]: 64692680L

In [207]: id(a[4])
Out[207]: 64692680L

In [208]: id(a) == id(a[4]) and id(a[4]) == id(a[5])
Out[208]: True

Notice first of all that += does not create an ellipsis list.

Secondly, it can be seen that the ellipsis-list indicates that accesing that slot will return the exact same list - the ellipsis-list represents a pointer to the outer list (or, almost certainly an outer list if there is more than one level of nesting).

Solution 3:

This is because a = a + a corresponds to a.extend(a) which "Extend the list by appending all the items in the given list". Another way to look at it is that the + operator results in "the concatenation of s and t".

This is in contrast to a += a which corresponds to a.append(a) which "adds an item at the end of the list".

Hope that clarifies things.

Post a Comment for "Ellipsis Lists [...] And Concatenating A List To Itself"