Recursive reference to a list within itself [duplicate]
Asked Answered
C

4

11

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?

Chirm answered 15/2, 2014 at 13:57 Comment(0)
C
8

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.

Chaffer answered 15/2, 2014 at 14:8 Comment(0)
O
3

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

Orchid answered 15/2, 2014 at 14:9 Comment(5)
Could you elaborate? You lost me at " It starts printing y : [ ??? ].....Chirm
Also what if I actually wanted a copy of the list? I know I can just do the same with y in this case, but for the sake of discussion is there a way I can do it?Chirm
@Sabyasachi: It is clearer that way ?Orchid
@Sabyasachi: This second question is very ambiguous. Which list are you talking about ? I think you should think about the difference between deep copy and shallow copy (see #185210)Orchid
Yes thanks it's clearer. I was talking about list l. Anyway I got it now. Thanks :)Chirm
H
2

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.

Hipolitohipp answered 15/2, 2014 at 14:20 Comment(0)
C
1

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

Centipoise answered 15/2, 2014 at 14:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.