So I came across something very weird in python. I tried adding a reference to the list to itself. The code might help demonstrate what I am saying better than I can express. I am using IDLE editor(interactive mode).
>>>l=[1,2,3]
>>>l.append(l)
>>>print(l)
[1,2,3,[...]]
>>>del l[:-1]
>>>print(l)
[[...]]
So far the output is as expected. But when I do this.
y=l[:]
print(y)
To me it seems that the output should be
[[...]]
But it is
[[[...]]]
Apparently instead of creating a copy of the list, it puts a reference to the list in y.
y[0] is l returns True. I can't seem to find a good explanation for this. Any ideas?
This is perfectly expected. When Python prints recursive lists, it checks that the list it is printing hasn't yet been encountered and if it has prints [...]
. An important point to understand is that it doesn't test for equality (as in ==
) but for identity (as in is
). Therefore,
when you print l = [l]
. You have l[0] is l
returns True
and therefore it prints [[...]]
.
now y = l[:]
makes a copy of l
and therefore y is l
returns False
. So here is what happens. It starts printing y
so it prints [ ??? ] where ???
is replaced by the printing of y[0]
. Now y[0]
is l
and is not y
. So it prints [[???]]
with ???
replaced by y[0][0]
. Now y[0][0]
is l
which has already been encountered. So it prints [...]
for it giving finally [[[...]]]
.
The difference is only in the way the list is displayed. I.e. the value of y
is exactly what you'd expect.
The difference in the way the lists are displayed results from the fact that, unlike l
, y
is not a self-referencing list:
l[0] is l
=> True
y[0] is y
=> False
y
is not self-referencing, because y
does not reference y
. It references l
, which is self-referencing.
Therefor, the logic which translates the list to a string detects the potential infinite-recursion one level deeper when working on y
, than on l
.
You need to have a full copy of the objects. You need to use copy.deepcopy
and you would see the expected results.
>>> from copy import deepcopy
>>> l=[1,2,3]
>>> l.append(l)
>>> print(l)
[1, 2, 3, [...]]
>>> del l[:-1]
>>> print(l)
[[...]]
>>> y=deepcopy(l)
>>> print(y)
[[...]]
>>> y[0] is l
False
>>>
When you use the slice notation to copy the list, the inner references are retained which cause the behavior that you observe.
Slicing generates list of items. There is only one item - list "l". So, we have new list of one element - list "l".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With