Reputation: 1021
I have a tree structure in Python where each node is a list [dict,int]. The dict points to the children. The leaves are plain ints, no lists to save memory. Now I want to scale the integer value in each node by a constant factor. I have written the following recursive function that takes the root node and the factor:
def scale(node,factor):
if type(node) != list:
node *= factor;
else:
node[1] *= factor;
for key in node[0]:
scale(node[0][key],factor);
I have the impression that the leave nodes are not changed because of some of these Python reference/dereference issues. Is this true?
Upvotes: 0
Views: 1189
Reputation: 375484
This statement doesn't do what you think:
node *= factor
This only multiplies the local variable node
, it won't modify the dict value you originally passed in. Ints are immutable, so there is no way to pass one into a function and have the function modify it in-place.
This article has details on how names and values work in Python: Facts and Myths about Names and Values in Python.
BTW: the best way to check a type is (if you must) is:
if not isinstance(node, list):
Upvotes: 1
Reputation: 1021
Since I am not going to change my data structure, I had to do the following (in my opinion this is one of these cases where Python sucks):
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);
And then change the root int separately before calling the recursion. Fortunately, in this case there might be the extra benefit that this should be faster because there is no function call for leave nodes...
Upvotes: 0
Reputation: 87054
This snippet explains why the leaf nodes (type int) are not updated:
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]
So you can see that n
is not changed because only the local variable x
is updated in function f(x)
. However, the list l
is updated because it is mutable.
Any easy way to fix this is to wrap your leaf nodes in a list
(or other mutable type) and store (and update) the leaf value. Then you can write scale()
like this:
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)
Upvotes: 1