Python 在递归函数参数中修改列表时,列表会发生什么情况

Python 在递归函数参数中修改列表时,列表会发生什么情况,python,backtracking,n-queens,Python,Backtracking,N Queens,这是n皇后问题的解决方案。在递归调用中,它传递修改过的列表。我的问题是,对于每个递归调用,它是否会创建三个新列表:queen、xy_dif、xy_sum,并将它们保留在调用堆栈中?或者只有这三个列表,每个递归调用只是在适当的地方修改它们?如果是这样,我不明白它是如何解决以下问题的: DFS([],[],[])调用DFS([0],[0],[0]),然后DFS([0],[0],[0])调用DFS([0,2],[0,-1],[0,3]),它没有通过if条件,因此返回 然后for循环继续,q=3,我的问

这是n皇后问题的解决方案。在递归调用中,它传递修改过的列表。我的问题是,对于每个递归调用,它是否会创建三个新列表:queen、xy_dif、xy_sum,并将它们保留在调用堆栈中?或者只有这三个列表,每个递归调用只是在适当的地方修改它们?如果是这样,我不明白它是如何解决以下问题的:

DFS([],[],[])调用DFS([0],[0],[0]),然后DFS([0],[0],[0])调用DFS([0,2],[0,-1],[0,3]),它没有通过if条件,因此返回

然后for循环继续,q=3,我的问题是为什么DFS([0,3],[0,-2],[0,4])是下一个调用,而不是DFS([0,2,3],[0,-1,-2],[0,3,4])

调用DFS([0]、[0]、[0])后,这三个列表如何恢复到原始状态

添加一些“标准”递归跟踪,您可以很容易地看到结果。在本例中,
id
函数是您的朋友,显示特定参数是否引用同一实体

正如您在下面的输出中所看到的,每个参数都有一个唯一的id:它是一个独立的对象。这是因为您尚未将一个调用的参数传递给下一个调用。而是在堆栈上创建了一个临时变量。例如,如果您只是通过
queens
,那么该列表引用将由所有调用共享

另一方面,
queens+[q]
不是
queens
;相反,它是一个新的列表表达式:堆栈上的一个临时变量,具有一个单独的值

如果您希望共享这些结构,请首先修改皇后区,然后将修改后的版本传递到下一级:

queens.append(q)
DFS(queens, xy_dif+[p-q], xy_sum+[p+q])
在这种用法中,
xy_diff
xy_sum
仍然是每次调用的独立变量,但是
queens
是共享的

使用递归检测的代码:

indent = ""

def DFS(queens, xy_dif, xy_sum):
    global indent
    print(indent, "ENTER DFS", queens, xy_dif, xy_sum)
    print(indent, "parameter IDs:", id(queens), id(xy_dif), id(xy_sum))
    indent += "  "

    print('call function DFS({},{},{})'.format(queens, xy_dif, xy_sum))
    p = len(queens)
    print('updated row p is ', p)

    if p==n:
        result.append(queens)
        print('p==n, result is ', result)
        indent = indent[2:]
        return None

    for q in range(n):
        print('loop starts, q is ', q)
        if q not in queens and p-q not in xy_dif and p+q not in xy_sum: 
            DFS(queens+[q], xy_dif+[p-q], xy_sum+[p+q])  

    result = []
    DFS([],[],[])
    send_back = [ ["."*i + "Q" + "."*(n-i-1) for i in sol] for sol in result]

    print(indent, "LEAVE DFS", queens, xy_dif, xy_sum)
    indent = indent[2:]
    return send_back
开始输出:

 ENTER DFS [] [] []
 parameter IDs: 1813255818376 1813255818888 1813255819016
call function DFS([],[],[])
updated row p is  0
loop starts, q is  0
   ENTER DFS [0] [0] [0]
   parameter IDs: 1813255827784 1813258276680 1813255818760
call function DFS([0],[0],[0])
updated row p is  1
loop starts, q is  0
loop starts, q is  1
loop starts, q is  2
     ENTER DFS [0, 2] [0, -1] [0, 3]
     parameter IDs: 1813255817480 1813255817352 1813255817928
call function DFS([0, 2],[0, -1],[0, 3])
updated row p is  2
loop starts, q is  0
loop starts, q is  1
loop starts, q is  2
loop starts, q is  3
       ENTER DFS [] [] []
       parameter IDs: 1813255817864 1813255817736 1813255816712
call function DFS([],[],[])
updated row p is  0
loop starts, q is  0
         ENTER DFS [0] [0] [0]
         parameter IDs: 1813255816392 1813255816264 1813255816136
call function DFS([0],[0],[0])
...

queens+[q]
和递归调用的其他两个参数正在构造新列表。它们引用与原始列表相同的项(如果这些项是可变的,例如子列表,那么这将是相关的),但是它们没有以其他方式连接到原始列表。是的,这实际上与递归无关,它与连接操作符的语义有关,
+
与列表对象。非常感谢您抽出时间。我一定会将此保存为模板,以备将来使用。
 ENTER DFS [] [] []
 parameter IDs: 1813255818376 1813255818888 1813255819016
call function DFS([],[],[])
updated row p is  0
loop starts, q is  0
   ENTER DFS [0] [0] [0]
   parameter IDs: 1813255827784 1813258276680 1813255818760
call function DFS([0],[0],[0])
updated row p is  1
loop starts, q is  0
loop starts, q is  1
loop starts, q is  2
     ENTER DFS [0, 2] [0, -1] [0, 3]
     parameter IDs: 1813255817480 1813255817352 1813255817928
call function DFS([0, 2],[0, -1],[0, 3])
updated row p is  2
loop starts, q is  0
loop starts, q is  1
loop starts, q is  2
loop starts, q is  3
       ENTER DFS [] [] []
       parameter IDs: 1813255817864 1813255817736 1813255816712
call function DFS([],[],[])
updated row p is  0
loop starts, q is  0
         ENTER DFS [0] [0] [0]
         parameter IDs: 1813255816392 1813255816264 1813255816136
call function DFS([0],[0],[0])
...