question on the topic of lists

v
veronica di gennaro (520 points)
1 2 3
asked Oct 13, 2021 in Programming in Python by veronica di gennaro (520 points)
if I take a list l1

>>> l1=[1, 2, 3, 4, 4, 5, 9]

and then a list l2=l1
>>> l2=l1

when I operate on l1 also l2 is modified, for example in this case:
>>> l1.reverse()
>>> l1
[9, 5, 4, 4, 3, 2, 1]
>>> l2
[9, 5, 4, 4, 3, 2, 1]

why does this happen?
165 views

5 Answers

simonemignanelli (2130 points)
1 2 22
answered Oct 13, 2021 by simonemignanelli (2,130 points)
A while ago I had the same doubt, if im not wrong is due to the fact that both variables l1 and l2 point to the same memory, however I leave you the link of the stackoverflow question that helped me.

(italian: Un po di tempo fa avevo lo stesso dubbio, se non erro è per il fatto che entrambe le variabili l1 ed l2 puntano sullo stesso blocco di memoria, comunque ti lascio il link della domanda stackoverflow che a me aveva aiutato.)

https://stackoverflow.com/questions/2612802/list-changes-unexpectedly-after-assignment-why-is-this-and-how-can-i-prevent-it
iacopomasi (2710 points)
13 19 38
answered Oct 13, 2021 by iacopomasi (2,710 points)

The assignment operator with lists will create an alias used in that way. That is, the variable l2 still refers to the same object pointed by l1. This explains what happens. If you want l1 to stay the same you have to create a copy of it.

You can see animations here copying and aliasing.

ruben.ciranni (4650 points)
7 13 31
answered Oct 13, 2021 by ruben.ciranni (4,650 points)
Because when you write l2 = l1 you are creating a new variable l2 that points to the same block of memory as l1 so when l1 is modified, also m2 is.

You can visualise this using Pytontutor
Luigi Pizza (6110 points)
11 19 65
answered Oct 13, 2021 by Luigi Pizza (6,110 points)
edited Oct 14, 2021 by Luigi Pizza

As everybody else said, when you write l2 = l1 you are not creating a new list, but pointing l2 to the same position in memory as l1.

If you want another list with the same elements then these are your choices of commands:

l2 = l1[:]

l2 = l1.copy()

import copy   \n   l2 = copy.copy(l1)

Moreover (and this is my "original" contribution to this discussion) obviously you can't do this with tuples, as they are not modifiable, and, in practise, if you have a tuple to modify, you first have to make it a list with the command - list1=list(tuple1) - (or you can create a new tuple based on the one before).

Things can get trickier if you have a list of tuples to convert, but you can use the following line of code to make it faster. So, for example:

list_of_tuples = [(1,2),(7,8),(‘Italy’,’France’)]

list_of_lists = [list(elements) for elements in list_of_tuples]

As straightforward as it may be from reading it, it means to transform each element in a list.

Same for going back:

list_of_lists=[[1,2],[7,8],[‘Italy’,’France’]]

list_of_tuples = [tuple(element) for element in list_of_lists]

Yes, I kind of got sidetracked, what I wanted to say is that this doesn't happen with tuples (their location is changed when you modify them to a list), as can be seen with:

tuple1 = (1,2,3,4,5,6)
tuple2 = tuple1
tuple1 = tuple(reversed(list(tuple1)))
print(tuple1, tuple2)

On PythonTutor.

ruben.ciranni (4650 points)
7 13 31
commented Oct 14, 2021 by ruben.ciranni (4,650 points)
There is a substantial difference in what happens with tuples and what happens with lists:

When you use l.reverse() the attribute reverse()  modifies the list and returns None, to prove that, try creating a list and then writing l = l.reverse(), you will notice that l now is None.

On the contrary, since as you said tuples are immutable, you can't directly reverse them: to reverse a tuple you first have to convert it to a list, then use the attribute .reverse() with the list, and convert it again to a tuple.

P.S. reversed isn't used to reverse a list or a tuple, but it returns a reverse iterator over the values of  the given sequence, so pay attention not to confuse between reversed() and .reverse() !
v
veronica di gennaro (520 points)
1 2 3
commented Oct 14, 2021 by veronica di gennaro (520 points)
Considering what you said about the difference between reversed() and .reverse()...

that's why I can do:

tuple1=tuple(reversed(tuple1))

and instead I can't directly use the attribute .reverse() on tuples, right?

Is it like I'm not operating on the tuple using revesed() ?
Luigi Pizza (6110 points)
11 19 65
commented Oct 14, 2021 by Luigi Pizza (6,110 points)
Veronica, Indeed, what you are saying is true. You can't use the attribute .reverse() on tuples because it reverses the elements in the container you are considering. reversed() doesn't modify anything, just returns an object that can be used to iterate over the tuple's elements in reverse order.
v
veronica di gennaro (520 points)
1 2 3
commented Oct 14, 2021 by veronica di gennaro (520 points)
Ok, I got it. Thanks for the explanation!
gianluca5539 (9820 points)
2 5 44
answered Oct 15, 2021 by gianluca5539 (9,820 points)
With that syntax you are only making another pointer to the same object in memory. If you change l1 or l2, you "change them both". If you want to create another list that is the same as the first but not only a pointer, you have to make a copy of that list. You can easily do it by calling the method copy()

l1 = [1,2,3]

l2 = l1.copy()

these are totally different lists now.