这个问题的灵感来自阅读DFS上的Edd Mann's post。
据我所知,如果一个可变对象作为函数参数传递,它的值适用于递归调用;如果将不可变对象作为函数参数传递,则其值将固定为每个递归调用。
让我举一些例子来说明我的意思,假设输入是
adj_list = {1: {2, 3}, 2: {1, 4}, 3: {1, 5}, 4: {2, 5}, 5: {3, 4}}
可变案例visited
是list
:
def dfs(adj_list, s, visited=None):
if visited is None:
visited = []
visited += [s]
for neighbor in adj_list[s]:
if neighbor not in visited:
dfs(adj_list, neighbor, visited)
return visited
返回:
[1, 2, 4, 5, 3]
不可变案例visited
是tuple
:
def dfs(adj_list, s, visited=None):
if visited is None:
visited = tuple()
visited += (s,)
for neighbor in adj_list[s]:
if neighbor not in visited:
dfs(adj_list, neighbor, visited)
return visited
返回:
(1,)
不明确的案例visited
是list
:
def dfs(adj_list, s, visited=None):
if visited is None:
visited = [s]
for neighbor in adj_list[s]:
if neighbor not in visited:
dfs(adj_list, neighbor, visited + [neighbor])
return visited
返回:
[1]
正如您可能观察到的那样,对于模糊的情况,可变list
对象被传递给递归调用,但答案与可变案例中的答案不同。我怀疑它是因为list
是通过函数参数而不是函数体传递的。
我希望有人可以帮我解决这两个方面,解释一下幕后发生的事情:
答案 0 :(得分:1)
我怀疑它是因为列表是通过函数参数传递的 功能体。
不,这是因为您传递了从列表添加中创建的新列表,您没有参考。
在原始情况下,列表就地扩展(通过+=
),这样在所有递归调用结束时,您的列表将收集所有递归调用的结果。将分配给可变对象的变量视为对内存中某些可扩展/可简化对象的引用更容易。
>>> l = []
>>> id(l)
4317346848
>>> l += [2]
>>> id(l)
4317346848 # same list
在不可变的情况下,为每个'就地创建一个新的元组对象。 +=
操作(在这种情况下不是这样)。递归调用的结果收集在全新的元组中,与根调用中的元组无关。这就是为什么你只能从第一个函数调用(1,)
得到结果。
>>> c = tuple()
>>> id(c)
4316020816
>>> c += (2,)
>>> id(c)
4317473616 # new tuple
不明确的情况类似于第二种情况,创建的列表是一个新列表(visited + [neighbor]
),与您的根调用中的原始visited
列表几乎没有关系递归。
>>> id(l+[2])
4317534832 # new list