Jakob Lovern
Jakob Lovern

Reputation: 21

Python function dereferences a pointer but still alters the original list

I was playing around with python for the last few days and I keep getting a weird problem. (For reference, I'm working on project euler's 345.) So... I'm trying to zero a row and a column of a 2D array, but not the point where they intersect. Now, I understand that there might be a more pythonic way of solving this, but I'm mainly concerned with why the code I have here isn't working.

def choose(initial_grid,row,col):
  """Return a grid with a given row and column zeroed except where intersect.
  """
  grid = list(initial_grid)                 #FLAG 1
  Special_value = grid[row][col] 
  grid[row] = [0]*len(grid[row]) 
  for i in xrange(len(grid)):
    grid[i][col] = 0
  grid[row][col] = Special_value
  return grid
qwer = [[ 1, 2, 3, 4],
        [ 5, 6, 7, 8],
        [ 9,10,11,12],
        [13,14,15,16]]
print choose(qwer,1,1)
print qwer

Anyways, I'd expect the function output to be

[[1, 0, 3, 4], [0, 6, 0, 0], [9, 0, 11, 12], [13, 0, 15, 16]]
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]

But... It isn't. For whatever reason, qwer gets its column 1 cleared. I've tried doing a list copy to dereference the pointer passed by initial_grid, and I've tried using grid = initial_grid[:], but nothing seems to work.

So what's wrong? How do I fix this? And why is this wrong?

Upvotes: 0

Views: 433

Answers (1)

timgeb
timgeb

Reputation: 78760

list(initial_grid) makes a shallow copy of your list. The inner lists are not copied.

Demo:

>>> l = [[1, 2], [0, 0]]
>>> c = list(l)
>>> l is c
False
>>> all(x is y for x,y in zip(l, c))
True
>>> c[0][0] = 5
>>> c
[[5, 2], [0, 0]]
>>> l
[[5, 2], [0, 0]]

If you want a deep copy, use copy.deepcopy. Or for a 2D list, write

>>> d = [sub[:] for sub in l]
>>> d[0][0] = 7
>>> d
[[7, 2], [0, 0]]
>>> l
[[5, 2], [0, 0]]

Also, your lingo is off. We don't have pointers in Python. We have names and values.

Upvotes: 1

Related Questions