0

The function update in the following code tries to update a tree in place. Since Python doesn't support pass by ref so the function update has a parameter of list (https://realpython.com/python-pass-by-reference/).

However, n was not updated after called update([n])?

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def update(ns):
    ns[0] = ns[0].left

n = TreeNode(1, TreeNode(2), TreeNode(3))
update([n])
# n is not updated, n should be replaced by the left child of the n (2).
ca9163d9
  • 27,283
  • 64
  • 210
  • 413
  • "Since Python doesn't support pass by ref" - any reference? Have you tried passing `n` directly? – Jan Stránský Sep 01 '20 at 22:53
  • 2
    Python always passes by object reference, why do you think it doesn't? You don't need to use a list at all. – Random Davis Sep 01 '20 at 22:54
  • @JanStránský "officially", Python passes "references by value" (or "by assignment"), but only for mutable objects. This has been heavily discussed, for example https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference – DeepSpace Sep 01 '20 at 22:55
  • @DeepSpace I was more interested in the OP's source. Passing `n` directly to `update` and modifying it inside the function would change it in-place, as OP wants. Because it is passed "by ref" – Jan Stránský Sep 01 '20 at 23:00
  • 1
    @JanStránský OP's situation is tricky because they want to change the object itself, not an attribute on it. Doing `def update(local_n): local_n = local_n.left` and calling `update(n)` will not modify the object that was passed to `update`, it will just create a new local variable `local_n` and dispose it, leaving the original unchanged – DeepSpace Sep 01 '20 at 23:02
  • working with trees is tricky by default :-) If the requirement is to modify in place, then OP should modify the tree in place. @ca9163d9, could you please provide expected output after `update`? – Jan Stránský Sep 01 '20 at 23:06
  • @JanStránský a TreeNode with val of 2 and no child. I've updated the question – ca9163d9 Sep 01 '20 at 23:15

4 Answers4

2
n = TreeNode(1, TreeNode(2), TreeNode(3))
update([n])
# n is not updated

No, n is not updated.

What's updated is [n], but you don't see it because you didn't keep a reference to it before passing it to update().

If you use

ns = [n]
update(ns)

you should see that ns has been changed.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
2

ns[0] and ns[0] = xxx are synthatic sugar in python:

ns[0] means item 0 of s and internaly calls ns.__getitem__(0)

ns[0] = xxx means item 0 of ns is replaced by xxx and internaly calls ns.__setitem__(0, xxx).

It is different than writing myvar = xxx.

so in your update function, you are only mutating the list ns which is only visible inside the function.

Cyril Jouve
  • 990
  • 5
  • 15
1

To update the tree in place, one option is to overwrite the attributes

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def update(n): # passed by reference!
    m = n.left # m ... node to be copied
    n.val,n.left,n.right = m.val,m.left,m.right # overwriting n attributes by m attributes

n = TreeNode(1, TreeNode(2), TreeNode(3))

print(n)
print(n.val,n.left,n.right) # original node
update(n)
print(n)
print(n.val,n.left,n.right) # changed node (but still the same instance)
Jan Stránský
  • 1,671
  • 1
  • 11
  • 15
1

In Python, variables are labels that map to a memory reference. a=b just remaps the reference for a to the reference for b. So what you're trying to do with lists shenanigans is literally what Python does automatically with the assignment operator:

def update(ns):
    return ns.left

n = TreeNode(1, TreeNode(2), TreeNode(3))
n = update(n)
Alex Weavers
  • 710
  • 3
  • 9