Difference between appending a variable and appending ['o']?


#1

I was tinkering with the code so I can control the size of the board. Below is that function but when I try to change an element in that list it gives me a wrong output and I don't know why.

MY VERSION

board = []

def setup(num):
    a = ['o'] * num
    for x in range(num):
        board.append(a)

setup(5)
board[1][1] = 'x'
print board

--------output-------

[['o', 'x', 'o', 'o', 'o'], ['o', 'x', 'o', 'o', 'o'], ['o', 'x', 'o', 'o', 'o'], ['o', 'x', 'o', 'o', 'o'], ['o', 'x', 'o', 'o', 'o']]

------------you see how there are 5 x?-------------

Correct version

board = []
    def setup(num):
        for x in range(num):
            board.append(['o']*num)

setup(5)
board[1][1] = 'x'
print board

--------output-------
[['o', 'o', 'o', 'o', 'o'], ['o', 'x', 'o', 'o', 'o'], ['o', 'o', 'o', 'o', 'o'], ['o', 'o', 'o', 'o', 'o'], ['o', 'o', 'o', 'o', 'o']]
-------one 'x' as I want---------

I honestly don't know the difference between my version and the other one, but the output clearly states the otherwise.
Can someone tell me the underlying difference here?


#2

That's a fun error! Your problem is that lists are mutable objects, meaning that when you do an operation on a list, you actually change the object. You bind the name 'a' to a list object. Then inside the for loop you append the list 'a' is bound to num times onto the 'board' list.

Every item in the list 'board' is the same object. Instead of appending 'a' directly you should append list(a) or a[:]. Both returns a new list that contains the same objects as 'a' did. Note that you don't have to worry about the 'o' in list being the same object as chars are immutable. It's a semi complicated, but very important to understand concept, and I'm not much of a teacher and possibly wrong about some term or detail, so do some googling about it.