在下面的函数中,当我使用path = path + [start]
然后我将得到结果['A', 'B', 'E']
但是当我使用path += [start]
然后我将得到结果['A', 'B', 'D', 'E']
。为什么?
我的代码:
graph1 = {'A':['B','C'],
'B':['A','D','E'],
'C':['A','F'],
'D':['B'],
'E':['B','F'],
'F':['C','E']}
def find_path(graph,start,end,path=[]):
path = path + [start]
if start == end:
return path
if start not in graph:
return None
for node in graph[start]:
if node not in path:
newpath = find_path(graph,node,end,path)
if newpath:
return newpath
return None
print(find_path(graph1,'A','E'))
这里有两件事:
首先,你在path=[]
定义中的find_path
是一个mutable default argument,如果你不期待它,它有一个非常令人惊讶的行为。简短的版本是path
的默认值不是每次都是新的[]
,而是每次都是相同的[]
。
其次,path = path + [start]
将名称path
重新命名为由连接创建的新list
对象,而path += [start]
则改变list
指向的现有path
对象。我可以想到的最好的资源来学习更多关于这种区别的文章是Facts and myths about Python names and values。
两者的结合意味着您每次都在改变相同的列表;如果您更改其中任何一个,您将获得单独的列表对象,而不会看到此问题。
问题来自于在find_path
定义中使用可变值作为默认参数。
path += [start]
时,你实际上改变了path
的默认值path = path + [start]
时,你实际上将path
参数存储在本地path
变量中,然后再进行更改。更多细节here
遗憾的是,对于列表,Python重载+=
意味着与list.extend
相同(在所有情况下而不仅仅是当差异不可见时),因此它将使用RHS就地扩展LHS,而正常的二进制+
将创建一个品牌新的列表对象,复制LHS,然后复制RHS。
这在这里是显而易见的,因为在Python中,默认值是在模块解析期间创建的并且绑定到函数本身,每次调用函数时都不会获得新值。因此,如果您就地修改path
(这是+=
所做的),它仍然在函数的调用之间。