user6175310
user6175310

Reputation: 55

When does mutability of python class objects affect assignments?

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?

Upvotes: 1

Views: 210

Answers (1)

kindall
kindall

Reputation: 184395

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.

Upvotes: 2

Related Questions