我正在尝试在python中编写一个算法来打印从(二进制)树的根到每个叶子的所有路径。这是我的代码:
def fb_problem(node, curr_trav):
curr_trav = curr_trav + [node]
if node.left is None and node.right is None:
for path_node in curr_trav:
print path_node.data
print "XXX"
if node.left is not None:
fb_problem(node.left, curr_trav)
if node.right is not None:
fb_problem(node.right, curr_trav)
fb_problem(root, [])
我在当前遍历中保留了一个节点列表,当我到达一个叶子时,我打印出列表。我误解了python传递对象的方式。我想当每个递归调用完成并从堆栈中弹出时,原始的curr_trav
变量不会受到递归调用的影响。但是,好像是行
curr_trav += [node]
正在改变原始列表。 +=
运算符返回一个新列表,而不是.append()
,它实际上会改变原始对象。所以这个调用不应该只是重新分配给函数中的对象的名称,而不是改变原始对象?当我将行更改为
t_trav = curr_trav += [node]
一切正常,但我不明白原始线的问题是什么。如果我的问题不清楚,请告诉我。
答案 0 :(得分:2)
使用python既不是值也不是引用。它是两者的组合,并且取决于传递给函数的对象的类型。例如,如果传递了诸如dict, list etc
之类的可变类型,它将传递引用。使用诸如str
之类的不可变类型,它将是值。关于这个主题的好读是Jeff Knupp。
原始代码curr_trav += [node]
的问题在于它将[node]
的值添加到curr_trav
并设置对新列表的引用。因为它传递了curr_trav
的引用,所以它将在每次后续迭代中被更改。
答案 1 :(得分:1)
您对+=
的理解并不完全正确。 Python中的所有运算符都只是快捷方式。例如,如果a + b
具有a.__add__(b)
方法,则a
为__add__
。如果a
没有,则为b.__radd__(a)
。如果b
没有该方法,则会引发错误。通常,a += b
的行为与a = a + b
非常相似,但在可变对象的情况下,它通常不会。这是因为如果a += b
具有a.__iadd__(b)
方法,则a
为__iadd__
。如果a
没有,则与a = a.__add__(b)
相同。如果a
也没有,则与a = b.__radd__(a)
相同。由于列表 do 具有__iadd__
方法,因此更改实际列表对象而不是重新定义curr_trav
。