Two names for one list
Up to now it has been fine to say that scores = [7, 9] puts a list in the variable scores. For lists, that way of thinking leads you astray. A variable doesn't hold the list itself: it holds a reference to it, which tells Python where the list is in the computer's memory. Think of the list as a house, and of the reference as the house's address written on a note.
Most of the time the difference doesn't matter. It matters as soon as two variables refer to the same list:
>>> todo = ["wash", "cook"]
>>> today = todo
>>> today.append("shop")
>>> today[0] = "rest"
>>> todo
['rest', 'cook', 'shop']today = todo doesn't copy the list. It copies the reference, the address, so todo and today are now two names for one and the same list. A change made through either name changes that one list, and both names see it. In a program this can be a surprise:
weekday_songs = ["Intro", "Rain", "Comets"]
weekend_songs = weekday_songs
weekend_songs.append("Party Time")
print("Weekdays:", weekday_songs)
print("Weekend:", weekend_songs)
Weekdays: ['Intro', 'Rain', 'Comets', 'Party Time']
Weekend: ['Intro', 'Rain', 'Comets', 'Party Time']Numbers and strings can't change
Why doesn't the same happen with numbers?
>>> x = 5
>>> y = x
>>> y += 1
>>> x
5
>>> y
6Numbers, strings and Booleans are immutable: nothing can change them. y += 1 doesn't change the number 5. It makes a new number, 6, and points y at it, while x still refers to 5. String methods work the same way: upper gives a new string and leaves the old one as it was. Lists are mutable: append, sort, remove, pop and assigning to an index all change the list itself, and every name that refers to it sees the change.
Giving a variable a new value is different from changing the list it refers to:
>>> todo = ["wash", "cook"]
>>> today = todo
>>> today = ["sleep"]
>>> todo
['wash', 'cook']today = ["sleep"] points today at a new list. The old list doesn't change, and todo still refers to it.
References inside lists
A matrix is a list that holds references to its rows. Taking a row out of a matrix gives you another name for that row, not a copy of it:
seats = [["free", "free"], ["free", "taken"]]
first_row = seats[0]
first_row[1] = "taken"
print(seats)
[['free', 'taken'], ['free', 'taken']]That's why row[j] = ... inside a loop over a matrix changes the matrix: row refers to one of its rows. But number *= 10 on a number taken from a row only points the variable number at a new number.