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?
1 Answer 1
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.
-
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 becomeNone
) Is this correct?user6175310– user617531007/20/2016 19:36:26Commented 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).kindall– kindall07/20/2016 20:06:09Commented Jul 20, 2016 at 20:06
-
one other question, everytime in the while loop
current
gets assigned tocurrent.right
so at this pointroot
andcurrent
are no longer pointing to the same tree object right? if this is the case, in the endroot
is returned. How doesroot
keep getting updated? and however this is happening, why is it not equal tocurrent
, i.e. why iscurrent
not returned?user6175310– user617531007/25/2016 03:03:45Commented 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, butroot
is a different node in the recursive calls.kindall– kindall07/25/2016 05:27:42Commented Jul 25, 2016 at 5:27
test=root
, you're copying the object itself, so of course theleft
variable will be the same as theleft
variable from the same object, because they are literally the same variable.