Reputation: 340
Python Experts,
I have been trying to implement BST using Python and here is my code for the insert function:
Draft 1:
def insert(self, val):
newNode = self._Node(val)
if (self._root is None):
self._root = newNode
else:
self._insert(self._root,val)
def _insert(self, node, val):
if node is None:
node = self._Node(val)
elif val >= node._val:
self._insert(node._right, val)
else:
self._insert(node._left, val)
But, I'm unable to construct the tree except the root. I'm guessing I messed up somewhere with the parameters passing over the two functions because when I modify the code as below, I get it alright:
Draft 2:
def insert(self, val):
newNode = self._Node(val)
if (self._root is None):
self._root = newNode
else:
self._insert(self._root,val)
def _insert(self, node, val):
if val >= node._val:
if node._right is None:
node._right = self._Node(val)
else:
self._insert(node._right, val)
else:
if node._left is None:
node._left = self._Node(val)
else:
self._insert(node._left, val)
I'm trying hard to understand why the draft 2 works but draft 1 doesn't. Any help here? Thanks in advance!
Upvotes: 2
Views: 78
Reputation: 21
I believe this is due to the fact that by doing :
node = self._Node(val)
in the _insert function you are not changing the value of the left/right node but binding the name node to a new _Node object, thus letting the left/right node as None.
On your second draft you are effectively affecting a new object to left / right node.
Here's a simple example to illustrate what happens on your code.
Guess what the print(test) will display?
test = [5, 5, 5]
def function(list):
list[0] = 10
list = range(1, 3)
function(test)
print test
If you think it will display [1,2] you're wrong .. it will actually display [10, 5, 5] because when doing list = range(1, 3) we are binding the name list to another object and not changing the first object it was bound to (the one test is actually bound to)
Upvotes: 1
Reputation: 96277
The fundamental misunderstanding you have is how variable assignment works and interacts with Python's evaluation strategy: call-by-sharing.
Essentially, in your first draft, when you do the following:
def _insert(self, node, val):
if node is None:
node = self._Node(val)
...
You are simply assigning to the name (variable) node
the value of self._Node(val)
but then when you leave the scope, the new object is destroyed! Even though node
used to refer to the value that was passed in by the method call, simple assignment doesn't mutate the object that is referenced by the name, rather, it reassigns the name.
In your second draft, however:
def _insert(self, node, val):
if val >= node._val:
if node._right is None:
node._right = self._Node(val)
else:
self._insert(node._right, val)
You are mutating an object i.e.: `node._right = self._Node(val)
Here is a simple example that is hopefully illuminating:
>>> def only_assign(object):
... x = 3
... object = x
...
>>> def mutate(object):
... object.attribute = 3
...
>>> class A:
... pass
...
>>> a = A()
>>> a
<__main__.A object at 0x7f54c3e256a0>
>>> only_assign(a)
>>> a
<__main__.A object at 0x7f54c3e256a0>
>>> mutate(a)
>>> a.attribute
3
Upvotes: 2