我在Python中有一个树结构,其中每个节点都是一个列表[dict,int]。该词汇指向孩子们。叶子是普通的,没有列表来节省内存。现在我想用常数因子缩放每个节点中的整数值。我编写了以下递归函数,它接受根节点和因子:
def scale(node,factor):
if type(node) != list:
node *= factor;
else:
node[1] *= factor;
for key in node[0]:
scale(node[0][key],factor);
我的印象是,由于某些Python引用/解除引用问题,保留节点没有更改。这是真的吗?
答案 0 :(得分:1)
这句话不符合您的想法:
node *= factor
这只会乘以局部变量node
,它不会修改你最初传入的dict值.Int是不可变的,所以没有办法将一个函数传递给函数并让函数修改它-place。
本文详细介绍了名称和值如何在Python中运行:Facts and Myths about Names and Values in Python。
BTW:检查类型的最佳方法是(如果必须):
if not isinstance(node, list):
答案 1 :(得分:1)
此代码段解释了为什么叶节点(类型为int)未更新的原因:
def f(x):
print "got x", x
x *= 10
print "set x to", x
>>> n = 123
>>> f(n)
got x 123
set x to 1230
>>> n
123
>>> l=[1]
>>> f(l)
got x [1]
set x to [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
>>> l
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
因此,您可以看到n
未更改,因为在函数x
中仅更新了局部变量f(x)
。但是,列表l
已更新,因为它是可变的。
解决此问题的任何简单方法是将叶节点包装在list
(或其他可变类型)中并存储(并更新)叶值。然后你可以像这样写scale()
:
def scale(node,factor):
if len(node) == 1: # leaf node is a list containing a single int
node[0] *= factor;
else:
node[1] *= factor;
for key in node[0]:
scale(node[0][key],factor)
答案 2 :(得分:0)
由于我不打算更改我的数据结构,所以我必须执行以下操作(在我看来,这是Python糟糕的情况之一):
def scale(node,factor):
for key in node[0]:
if type(node[0][key]) != list:
node[0][key] *= factor;
else:
node[0][key][1] *= factor;
scale(node[0][key],factor);
然后在调用递归之前单独更改root int。幸运的是,在这种情况下可能会有更多的好处,因为没有函数调用离开节点...