1

My understanding of python's mutable feature for classes/objects is that if you make an assignment then any change to the original changes the assigned variable/object as well. I confused about this piece of code below.

# Recursive solution to Flatten Binary Tree to Linked List by LeetCode
# Definition for a binary tree node
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
 # @param root, a tree node
 # @return root, a tree node
 def flattenHelper(self, root):
 if root == None:
 return None
 else:
 left = root.left
 right = root.right
 root.left = None # Truncate the left subtree
 current = root
 # Flatten the left subtree
 current.right = self.flattenHelper(left)
 while current.right != None: current = current.right
 # Flatten the right subtree
 current.right = self.flattenHelper(right)
 return root
 # @param root, a tree node
 # @return nothing, do it in place
 def flatten(self, root):
 self.flattenHelper(root)
 return

Question: How come the variable left does not automatically get set to None once root.left = None is executed?

John Kugelman
364k70 gold badges554 silver badges599 bronze badges
asked Jul 20, 2016 at 18:56
9
  • 1
    root.left = None sets the name root.left to bind to None. It doesn't change what left is bound to. So the Node still exists, since something is referencing it. it is just that root.left doesn't reference it anymore Commented Jul 20, 2016 at 19:00
  • @joelgoldstick Thank you, but I am still confused: if I do the following: test=root, root.left=TreeNode(5), test.left.val will now be 5 why does the same thing not happen above? Commented Jul 20, 2016 at 19:04
  • @joelgoldstick I thought something similar to mutability of lists is happening here: if I have a=[1,2,3], then define b=a, now if I change a[0]=0, b[0] will change automatically as well. I tried this with objects, like the example above and a similar thing happened. I don't understand what is different about the implementation of this code, that left does not get set to None automatically. Commented Jul 20, 2016 at 19:09
  • "My understanding of python's mutable feature for classes/objects is that if you make an assignment then any change to the original changes the copy as well." - wrong. There is no copy. See nedbatchelder.com/text/names.html Commented Jul 20, 2016 at 19:10
  • @user6175310 with you example involving test=root, you're copying the object itself, so of course the left variable will be the same as the left variable from the same object, because they are literally the same variable. Commented Jul 20, 2016 at 19:14

1 Answer 1

2

Assignment in Python always works the same way. It changes the thing on the left side of the = sign to refer to the value of the expression on the right side. There is absolutely nothing whatsoever "different in the implementation" as you ask in a comment.

Sometimes the item on the left side is a slot in a container (a list, a dictionary, an object). These objects are mutable (able to be changed), so you can change what their slots refer to. When you do, for example:

a = b = [0]

Now a and b are two different names for the same object. If you do a[0] = 1 then b[0] also becomes 1, because a and b are the same object, and the assignment doesn't change this because you are assigning to slot 0 within the object referenced by a; you are not changing what a itself refers to. But if you instead do a = [1], then b[0] remains 0, because a now points to a different list from b.

This is what's happening in your example. The names left and root.left initially refer to the same object. When you change root.left to point to a different object, it doesn't change left to point to the same object. For that to happen, left would have to be a container, and it would have to be the same container as root, not root.left, and what would change would be left.left, not left itself. Because you can't change the value of a name by any way other than assigning to it.

answered Jul 20, 2016 at 19:20
4
  • Thank you! So basically if instead of assigning root.left to None, some change was made to the object (e.g. root.left.left = None, then this would change left ---> left.left would also become None) Is this correct? Commented Jul 20, 2016 at 19:36
  • Something like that. The rule of thumb is that you're only going to see a change to one object reflected in another object when the assignment is to a slot within an object (e.g. a list or dictionary item, or an object attribute), and only then if the other reference is to the same containing object (or a parent object, to be complete). Commented Jul 20, 2016 at 20:06
  • one other question, everytime in the while loop current gets assigned to current.right so at this point root and current are no longer pointing to the same tree object right? if this is the case, in the end root is returned. How does root keep getting updated? and however this is happening, why is it not equal to current, i.e. why is current not returned? Commented Jul 25, 2016 at 3:03
  • The function is recursive. After handling the root node, it calls itself to handle its left and right children. These function calls do the same with their children, and so on. root never gets updated in the initial function, but root is a different node in the recursive calls. Commented Jul 25, 2016 at 5:27

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.