0

I have a tuple like this.

t = (5, (3, (20, none, none), (21, none, none)), (10, (1, none, none), none))

I would like to build a tree from it. Tree class look like this.

class TreeNode(object):
    def __init__(self,x=None,l=None,r=None):
        self.x = x
        self.l = l  # left node
        self.r = r  # right node

I am building tree recursively. I check if the current node is None, then set current node to a new TreeNode class. But this doesn't work as expected.

def build(current_node, tupl):
    if tupl:
        if current_node is None:
            current_node  = TreeNode() # I think this removes link to the trees node.
        current_node.x = tupl[0]
        build(current_node.l, tupl[1])
        build(current_node.r,tupl[2])

here is how I call build function

root = TreeNode() # TreeNode is tree class
build(root,t)
# I try to print the tree level by level but tree only has root node

But this build function works fine.

def build(curr,t):
    if t:
        curr.x = t[0]
        try:
            if t[1] is not None:
                curr.l = TreeNode()
                build(curr.l,t[1])
        except Exception:
            pass
        try:
            if t[2] is not None:
                curr.r = TreeNode()
                build(curr.r,t[2])
        except Exception:
            pass

I am trying to understand why the first build function is failing.

Praveen Singh Yadav
  • 1,831
  • 4
  • 20
  • 31
  • 6
    What is wrong with your code - is there an error message or an incorrect output? Please post the traceback or expected and actual output. BTW, the "except Exception" is dangerous and can easily hide bugs. https://stackoverflow.com/questions/21553327/why-is-except-pass-a-bad-programming-practice . I'm also not clear on how the question body is related to the title - but no, None is not mutable. – perigon Jul 26 '17 at 04:15
  • Thanks, I will edit my question and emphasize on my problem. I am using try catch for checking if the index exists. how can do it without try catch? – Praveen Singh Yadav Jul 26 '17 at 05:13

1 Answers1

2

In Python, you can't reassign variables within a function, and have those values be visible to the calling context. By calling current_node = TreeNode(), current_node is assigned to a new object not visible to the outside.

def build(current_node, tupl):
    if tupl:
        if current_node is None:
            current_node  = TreeNode()
        current_node.x = tupl[0]

        build(current_node.l, tupl[1])
        build(current_node.r,tupl[2])

In your second example, you are passing in a TreeNode instance, then manipulating it's attributes and not reassigning it. Therefore, curr.l/curr.r in the current context and curr in the next call still refer to the same object.

def build(curr,t):
    if t:
        curr.x = t[0]
     ....
    if t[2] is None:
        curr.r = TreeNode()
     ....
     # reference link is not broken
     build(curr.r, t[2])
Xingzhou Liu
  • 1,507
  • 8
  • 12
  • Your distinction between primitives type and complex types is not correct. Python doesn't have different kinds of types like that. All objects are treated the same when passed as arguments. Python's calling convention is best described as "pass by name binding", since all function parameters are local variables bound to the objects passed in as arguments. – Blckknght Jul 26 '17 at 04:48
  • You're right. I was thinking that it is equivalent, but it's not. – Xingzhou Liu Jul 26 '17 at 04:55