Search code examples
pythonpython-2.7nestedpass-by-referencenested-function

Not able to do pass by value in python inside a nested function


I want to pass a new instance of 2D array to a function. I have tried the common answers like using the list(old) or doing a old[:]. Still I am getting the same reference.
The only reason I can think of is using nested methods which I don't understand well due to my C background. If anyone can explain why the code is behaving in this way it would really help me understand the magic of python.

Code for reproduction (Edited to make it minimal and more descriptive)-

from pprint import pprint as pp
class Solution:
    def solveNQueens(self, a):
        b1 = [['.' for i in range(a)] for j in range(a)]    #base list with queens positions and empty positions
        b2 = list(b1)   #to make a seperate list with na positions marked as x

        def fillRows(i, j, b, p):
            b[i][j] = 'Q' #add queens position
            for x in range(i + 1, a):
                p[x][j] = 'x'       #cross straight entries
            return b, p

        def queenFill(i, b, p):
            for j, e in enumerate(p[i]):
                if e == '.':
                    pp(p)
                    bx = []
                    bx.extend(b)    # trying to create new array duplicate that original array is unaffected by fillRows
                                    # but as seen from print p is getting changed still, it should be same for every print call
                    px = []
                    px.extend(p)
                    bt, pt = fillRows(i, j, list(bx), list(px)) #trying to create new array duplicate using another method

        queenFill(0, b1[:], b2[:]) #trying to create new array duplicate using another method 

s = Solution()
s.solveNQueens(4)

The output I am getting is -

[['.', '.', '.', '.'],
 ['.', '.', '.', '.'],
 ['.', '.', '.', '.'],
 ['.', '.', '.', '.']]
[['Q', '.', '.', '.'],
 ['x', '.', '.', '.'],
 ['x', '.', '.', '.'],
 ['x', '.', '.', '.']]
[['Q', 'Q', '.', '.'],
 ['x', 'x', '.', '.'],
 ['x', 'x', '.', '.'],
 ['x', 'x', '.', '.']]
[['Q', 'Q', 'Q', '.'],
 ['x', 'x', 'x', '.'],
 ['x', 'x', 'x', '.'],
 ['x', 'x', 'x', '.']]

While it should be like this as I am not changing the varible I am printing anywhere, I am creating duplicate of that -

   [['.', '.', '.', '.'],
     ['.', '.', '.', '.'],
     ['.', '.', '.', '.'],
     ['.', '.', '.', '.']],
[['.', '.', '.', '.'],
     ['.', '.', '.', '.'],
     ['.', '.', '.', '.'],
     ['.', '.', '.', '.']]
[['.', '.', '.', '.'],
     ['.', '.', '.', '.'],
     ['.', '.', '.', '.'],
     ['.', '.', '.', '.']]
[['.', '.', '.', '.'],
     ['.', '.', '.', '.'],
     ['.', '.', '.', '.'],
     ['.', '.', '.', '.']]

Solution

  • b1 is a list that contains inner lists. Copying it, either using list(b1) or b1[:] copies the outer list, but not the inner lists.

    If you want to copy the inner lists as well, try using copy.deepcopy.