0

I'm new to programming. I have written some Python code that has me confused. I have a list called "board" and I created a new list called "newlist". I created newlist using a function called cupdateboard(), that takes the list, board, and one other parameter as inputs. I'm not expecting board to change, yet it does. Can someone explain to me why board has changed, and how I could create newboard, based on board, without changing board?

def cupdateboard(cmove,lst):
    newlst=lst
    number=cmove+newlst[cmove]
    newlst[cmove]=0
    if number<=13:
        for i in range(cmove+1,number+1):
            newlst[i]+=1
    elif number>13 and number<=19:
        for i in range(cmove+1,14):
            newlst[i]+=1
        for i in range(0,number-13):
            newlst[i]+=1
    elif number>19:
        for i in range(cmove+1,14):
            newlst[i]+=1
        for i in range(0,6):
            newlst[i]+=1
        for i in range(7,7+(number-19)):
            newlst[i]+=1

    return newlst

board=[4,4,4,4,4,4,0,4,4,4,4,4,4,0]
cmove=7
newboard=cupdateboard(cmove,board)
print(newboard)
print(board)
input("Press enter to quit")
  • 2
    `board` is simply a reference to the memory that holds your list. When you pass `board` to functions, it stills references the same block of memory. Try searching "reference vs value types in Python". – Luke Joshua Park Apr 13 '16 at 00:16
  • You may also want to check out https://sopython.com/ and specifically http://sopython.com/canon/39/assigning-a-list-does-not-make-a-copy/ – tripleee Apr 13 '16 at 04:36

1 Answers1

3

Why This Happens

Assignment of a mutable data type in Python creates a shallow copy of the data type.

In other words, doing

s = [1,2,3]
v = s
v[0] = 200

results in s becoming [200, 2, 3] as well.

A shallow copy of s means v creates a new copy of s whose elements refer to the original elements of s in memory - v[i] points to the memory location that the original s[i] references, rather than to a new location in memory with a copy of s[i]. Obviously, that means when you change v[i], you overwrite the memory location, so that, when s[i] goes to look at its value, it sees a new value and returns that when asked.

This is what's happening here when you do newlst = lst, and making changes to newlst[i]. You're accidentally modifying lst[i] as well because of how shallow copying works. The same issue arises with dictionaries and other mutable objects. (Immutable objects, like strings, tuples, etc. do not experience this issue because, well, they're immutable).

The Solution

To get around this, you want to deep copy instead - create a new copy of s where all the elements point to brand new values of the elements (i.e. not pointing to the same memory location of the original s's elements, but taking the same elements, making a copy of each element in a brand new spot of memory locations, and having v[i] point to that new memory location).

Simply doing

from copy import deepcopy
...
def cupdateboard(cmove,lst):
    newlst = deepcopy(lst)

should solve your problems.

Akshat Mahajan
  • 9,543
  • 4
  • 35
  • 44