Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive reference to a list within itself [duplicate]

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?

like image 917
Guy Avatar asked Feb 15 '14 13:02

Guy


4 Answers

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 [[[...]]].

like image 22
hivert Avatar answered Nov 12 '22 18:11

hivert


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.

like image 103
shx2 Avatar answered Nov 12 '22 18:11

shx2


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.

like image 2
devnull Avatar answered Nov 12 '22 18:11

devnull


Slicing generates list of items. There is only one item - list "l". So, we have new list of one element - list "l".

like image 1
Yuriy Kovalev Avatar answered Nov 12 '22 17:11

Yuriy Kovalev