8

I found an "interesting" question about list.

list1 = [1, 2, 3]
list1.insert(3, list1)
print(list1)
[1, 2, 3, [...]]
POP = list1.pop()
print(POP)
[1, 2, 3]
list1.extend(['a', 'b', 'c'])
print(POP)
[1, 2, 3, 'a', 'b', 'c']

Those are shown in the interactive mode. Of course, I know "insert" can only insert one object into the list. However when I insert list1 into list1. It shows [...], what does it mean? Moreover, POP = list1.pop(), isn't that pop can only return the final object to you? After extend the list, the final object should be 'c'. Why it returns the whole list1 but without [...]?

Nirmi
  • 356
  • 3
  • 11
Dickson
  • 113
  • 6

3 Answers3

4

When you call list1.insert(3, list1) you are inserting a reference to list1 at index 3, so your list becomes:

[1, 2, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, [...

You can see this by doing:

>>> list1[3]
[1, 2, 3, [...]]
>>> list1[3][3]
[1, 2, 3, [...]]
>>> list1[3][3][3]
[1, 2, 3, [...]]
>>> list1[3][3][3][3]
[1, 2, 3, [...]]

You have infinitely nested list1 within itself, this is why you see [...] because the list is infinitely long.

When you then call POP = list.pop() you are removing the reference and so list1 becomes [1, 2, 3] again, and POP becomes a reference to list1.

Because POP is a reference to list1 when you call list1.extend(['a', 'b', 'c']) you also update POP as they're both pointing to the same list.


If instead you did:

list1 = [1, 2, 3]
list1.insert(3, list1[:])

You're adding a copy of list1 and so will get:

[1, 2, 3, [1, 2, 3]]

And then calling:

POP = list1.pop()

Will make POP a reference to the new list.

At this point doing:

list1.extend(['a', 'b', 'c'])
print(POP)

Will output:

[1, 2, 3]

and:

print(list1)

will output:

[1, 2, 3, 'a', 'b', 'c']

Alternatively, refer to this crude drawing (which is not truly representative):

enter image description here

Nick is tired
  • 6,860
  • 20
  • 39
  • 51
1

Wrt your first question. You are right that insert can add a single element to the list. However, that element can be anything - another number, a string, a complex object, a list, or even the list itself. Seems like Python is smart enough to figure out that printing list1 would result in an infinite output, since list1 has a cyclic structure like that. So it prints a placeholder which looks liks [...].


Wrt your second question. Since pop returns the last element in the list, but that element is a reference to the list itself you get that reference. It also removes the reference, so it seems to you that you're getting a copy of the original list. Which is true, but the object itself has suffered the addition and removal of its last element, as you would expect.

Horia Coman
  • 8,681
  • 2
  • 23
  • 25
0

Basically, Python is reference based for when we assign an object to other its reference is copied. For copying, you need deepcopy or slicing in case of a list. Below is the explanation in comments.

list1 = [1, 2, 3]
#Creating list 1
list1.insert(3, list1)
#Inserting list1 refrence at index 3, means inserting its refernce. It would become [1, 2, 3, [1, 2, 3, [1, 2, 3, [... so on]]]]

print(list1)
[1, 2, 3, [...]]
#in order to avoid this write like list1.insert(3, list1[:])

POP = list1.pop()
#Here pop is removing last index from list and returing modified list too

print(POP)
[1, 2, 3]
list1.extend(['a', 'b', 'c'])
# Here you are extending some other list not its refrence as previous
print(POP)
[1, 2, 3, 'a', 'b', 'c']
Rakesh Kumar
  • 4,319
  • 2
  • 17
  • 30