python copy()但列表似乎是通过副本传递的

时间:2017-09-17 14:02:48

标签: python copy parameter-passing

我在https://brilliant.org/wiki/recursive-backtracking/

找到了这段代码
from itertools import *
from copy import copy

def is_distinct( list ):
    '''Auxiliary function to is_solved
    checks if all elements in a list are distinct
    (ignores 0s though)
    '''
    used = []
    for i in list:
        if i == 0:
            continue
        if i in used:
            return False
        used.append(i)
    return True


def is_valid( brd ):
    '''Checks if a 3x3 mini-Sudoku is valid.'''
    for i in range(3):
        row = [brd[i][0],brd[i][1],brd[i][2]]
        if not is_distinct(row):
            return False
        col = [brd[0][i],brd[1][i],brd[2][i]]
        if not is_distinct(col):
            return False
    return True

def solve( brd , empties = 9):
    '''
      Solves a mini-Sudoku
      brd is the board
      empty is the number of empty cells
    '''

    if empties == 0:
        #Base case
        return is_valid( brd )
    for row,col in product(range(3),repeat=2):
        #Run through every cell
        cell = brd[row][col]
        if cell != 0:
            #If its not empty jump
            continue
        brd2 = copy( brd )
        for test in [1,2,3]:
            brd2[row][col] = test
            if is_valid(brd2) and solve(brd2,empties-1):
                return True
            #BackTrack
            brd2[row][col] = 0
    return False

Board = [ [ 0 , 0 , 0 ],
          [ 1 , 0 , 0 ],
          [ 0 , 3 , 1 ] ]
solve( Board , 9 - 3 )


for row in Board:#Prints a solution
    print row      

它返回正确的结果,表示已解决的板。

我不明白的是,solved()递归函数修改了Board列表,但该函数从不写入brd,它只写入brd2 },这是一个副本。

但是,当列表最后打印时,它会显示它已写入。

所以我对这段代码感到有点困惑,我知道python函数通过引用传递列表,但是这个例子明确地使用了copy()。我对复制感到困惑或者遗漏了什么。

2 个答案:

答案 0 :(得分:2)

copy.copy制作浅拷贝。在您的情况下,您有一个列表列表,浅拷贝只是创建一个新列表,但所有元素(内部列表)仍然引用旧列表:

>>> a = [[1,2,3], [2,3,1], [3,1,2]]
>>> b = copy(a)
>>> b[0][0] = 100
>>> a
[[100, 2, 3], [2, 3, 1], [3, 1, 2]]
>>> b 
[[100, 2, 3], [2, 3, 1], [3, 1, 2]])

在这种情况下,如果你根本不复制它甚至可以工作,例如

brd2 = brd

一般情况下,您可以使用deepcopy解决此问题,无需回溯或回溯但无需复制。但是复制和回溯相结合似乎有点浪费。

答案 1 :(得分:0)

您正在创建副本 浅拷贝就像你有一个物体,它有对其他物体的引用 因此,如果复制主对象,则尚未复制其内部引用。它仍然指向与前主对象相同的对象。

详细了解HERE

  

浅层复制和深层复制之间的区别仅与复合对象(包含其他对象的对象,如列表或类实例)相关:

     
      
  • 浅复制构造一个新的复合对象,然后(尽可能)将对它的引用插入到原始对象中。

  •   
  • 深层复制构造一个新的复合对象,然后递归地将原件中的对象的副本插入其中。

  •