I'm reading How to think like a computer scientist which is an introductory text for "Python Programming".
I want to clarify the behaviour of multiply operator (*
) when applied to lists.
Consider the function make_matrix
def make_matrix(rows, columns):
"""
>>> make_matrix(4, 2)
[[0, 0], [0, 0], [0, 0], [0, 0]]
>>> m = make_matrix(4, 2)
>>> m[1][1] = 7
>>> m
[[0, 0], [0, 7], [0, 0], [0, 0]]
"""
return [[0] * columns] * rows
The actual output is
[[0, 7], [0, 7], [0, 7], [0, 7]]
The correct version of make_matrix is :
def make_matrix(rows, columns):
"""
>>> make_matrix(3, 5)
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
>>> make_matrix(4, 2)
[[0, 0], [0, 0], [0, 0], [0, 0]]
>>> m = make_matrix(4, 2)
>>> m[1][1] = 7
>>> m
[[0, 0], [0, 7], [0, 0], [0, 0]]
"""
matrix = []
for row in range(rows):
matrix += [[0] * columns]
return matrix
The reason why first version of make_matrix fails ( as explained in the book at 9.8 ) is that
...each row is an alias of the other rows...
I wonder why
[[0] * columns] * rows
causes ...each row is an alias of the other rows...
but not
[[0] * columns]
i.e. why each [0]
in a row is not an alias of other row element.
Multiply two lists using for loop We can simply get the product of two lists using for loop. Through for loop, we can iterate through the list. Similarly, with every iteration, we can multiply the elements from both lists. For this purpose, we can use Zip Function.
Multiplying a list sequence by a float number. Similar to strings and tuples, lists are also considered a sequence object in Python. Hence trying to multiply a list by a float will also throw a type error.
Lists and strings have a lot in common. They are both sequences and, like pythons, they get longer as you feed them. Like a string, we can concatenate and multiply a Python list.
Python List also includes the * operator, which allows you to create a new list with the elements repeated the specified number of times.
EVERYTHING in python are objects, and python never makes copies unless explicity asked to do so.
When you do
innerList = [0] * 10
you create a list with 10 elements, all of them refering to the same int
object 0
.
Since integer objects are immutable, when you do
innerList[1] = 15
You are changing the second element of the list so that it refers to another integer 15
. That always works because of int
objects immutability.
That's why
outerList = innerList * 5
Will create a list
object with 5 elements, each one is a reference to the same innerList
just as above. But since list
objects are mutable:
outerList[2].append('something')
Is the same as:
innerList.append('something')
Because they are two references to the same list
object. So the element ends up in that single list
. It appears to be duplicated, but the fact is that there is only one list
object, and many references to it.
By contrast if you do
outerList[1] = outerList[1] + ['something']
Here you are creating another list
object (using +
with lists is an explicit copy), and assigning a reference to it into the second position of outerList
. If you "append" the element this way (not really appending, but creating another list), innerList
will be unaffected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With