I have a simple program above that creates a BST from a sorted array. It should parse the tree without showing the leaves which are essentially None. Could someone help explain why the program still spits out 'None'. I'm a python NooB and would appreciate any help.I have tried != 'None' along with is None but get the same results.
class Node:
def __init__(self,value):
self.value=value
self.nodeleft=None
self.noderight=None
def makeBST(ia,start,end,tree):
if (end < start):
return None
mid = (start + end) / 2
n = Node(ia[mid])
n.nodeleft = makeBST(ia, start, mid-1, tree)
n.noderight = makeBST(ia, mid+1, end, tree)
tree.append(n)
return n
def printBST(root):
print 'RR' ,root.value
if root.nodeleft == None:
print 'EOT'
else:
print printBST(root.nodeleft)
if root.noderight == None:
print 'EOT'
else:
print printBST(root.noderight)
if __name__ == '__main__':
array = [1, 2, 3, 4, 5, 6]
dic = []
root = makeBST(array, 0, len(array)-1, dic)
printBST(root)
The problem is that your code was passing the return value of printBST to print. Since printBST does not return anything, None was printed.
So when you wrote:
print printBST(root.nodeleft)
that code is certain to print None because printBST does not contain a return statement and so defaults to returning None.
You need to change printBST to do this:
def printBST(root):
print 'RR' ,root.value
if root.nodeleft is None:
print 'EOT'
else:
printBST(root.nodeleft)
if root.noderight is None:
print 'EOT'
else:
printBST(root.noderight)
Note also that using is is the correct way to test for None.
That said, you can make your code simpler like this:
def printBST(root):
if root is None:
print 'EOT'
return
print 'RR', root.value
printBST(root.nodeleft)
printBST(root.noderight)
As well as being simpler, this code has the additional benefit of not failing when presented with an empty tree.
printBST should return the values, and not print them. Because it does not return anything, it defaults to None. That is why printBST(root) is None
printBST(root) by itself won't print the value on its own. You have to put a print before:
print printBST(root)
Per PEP 8, you should never compare the NoneType singleton with equality operators (eg == and !=). Use is None and/or is not None
Related
I would like to inquire about the scope in Python of an object that is a class variable.
import numpy as np
class treeNode:
def __init__(self,key):
self.leftChild = None
self.rightChild = None
self.value = key
def insert(root,key):
if root is None:
return treeNode(key)
else:
if root.value == key:
return root
elif root.value<key:
root.rightChild = insert(root.rightChild,key)
else:
root.leftChild = insert(root.leftChild,key)
return root
def insert_1(root,key):
if root is None:
root = treeNode(key)
else:
if root.value<key:
insert_1(root.rightChild,key)
elif root.value>key:
insert_1(root.leftChild,key)
def construct_tree(a):
def insert_1(root,key):
if root is None:
root = treeNode(key)
else:
if root.value<key:
insert_1(root.rightChild,key)
elif root.value>key:
insert_1(root.leftChild,key)
root = treeNode(a[0])
for k in a:
insert_1(root,k)
return root
if __name__ == '__main__':
np.random.seed(1)
a = np.random.rand(12)
tree = treeNode(a[0])
for k in a:
insert(tree,k)
for k in a:
insert_1(tree,k)
tree_1 = construct_tree(a)
The insert() function produces the whole tree while insert_1() and construct_tree() which do not return anything fail to do so. Is there a function to recursively construct the whole tree without using a return statement? Thank you very much.
In insert, the base case of the recursion is when you're inserting into an empty subtree, represented by None being passed in as root. It works because you can create and return a new treeNode in that case, and the caller will do the right thing with the return value.
If you don't want to be using return, you need to push that base case up to the calling code, so it avoids making a call when a leaf node is going to be added:
def insert_no_return(root, key):
assert(root != None) # we can't handle empty trees
if root.key == key:
return # no value here, just quit early
elif root.key < key:
if root.rightChild is None: # new base case
root.rightChild = treeNode(key)
else:
insert_no_return(root.rightChild, key) # regular recursive case, with no assignment
elif root.key > key:
if root.leftChild is None: # new base case for the other child
root.leftChild = treeNode(key)
else:
insert_no_return(root.leftChild, key) # no assignment here either
That's a bit more repetitive than the version with return, since the base case needs to be repeated for each possible new child, but the recursive lines are a bit shorter since they don't need to assign a value anywhere.
As the assert says at the top, you can't usefully call this on an empty tree (represented by None), since it has no way to change your existing reference to the None root. So construct_tree probably needs special logic to construct empty trees. Your current version of that function doesn't handle empty input at all (and redundantly tries to add the root value to the tree a second time):
def construct_tree(a):
if len(a) == 0: # special case to construct an empty tree
return None
it = iter(a) # use an iterator to avoid redundant insertion of a[0]
root = treeNode(next(it))
for k in it:
insert_no_return(root, k)
Before asking, I searched out some old questions and get a better idea to put the "return" in front of the inside re-invocated the function to get the expected result.
some of them like:
How to stop python recursion
Python recursion and return statements. But when I do the same thing with my problem, it gets worse.
I have a Binary Search Tree and want to get the TreeNode instance by given a node's key, so it looks an easier traversal requirement and I already easily realized similar functions below, with which I did NOT put return in front of the function:
#preorder_List=[]
def preorder(treeNode):
if treeNode:
preorder_List.append(treeNode.getKey())
preorder(treeNode.has_left_child())
preorder(treeNode.has_right_child())
return preorder_List
so for my new requirement, I compose it like below first:
def getNode(treeNode,key):
if(treeNode):
if(treeNode.key==key):
print("got it=",treeNode.key)
return treeNode
else:
getNode(treeNode.left_child(),key)
getNode(treeNode.right_child(),key)
then the issue occurs, it finds the key/node but kept running and report a None error finally and then I put return in front of the both left and right branch like below:
def getNode(treeNode,key):
if(treeNode):
if(treeNode.key==key):
print("got it=",treeNode.key)
return treeNode
else:
return getNode(treeNode.left_child(),key)
return getNode(treeNode.right_child(),key)
but this makes the thing worse, it did reach the key found and return None earlier.
Then I tried to remove one "return" for the branch, no matter right or left. It works (Update: this worked when my test case contains only 3 nodes, when I put more nodes, it didn't work, or to say if the expected node is from right, then put return in front of right branch invocation works, for left one, it didn't). What's the better solution?
You need to be able to return the results of your recursive calls, but you don't always need to do so unconditionally. Sometimes you'll not get the result you need from the first recursion, so you need to recurse on the other one before returning anything.
The best way to deal with this is usually to assign the results of the recursion to a variable, which you can then test. So if getNode either returns a node (if it found the key), or None (if it didn't), you can do something like this:
result = getNode(treeNode.left_child(),key)
if result is not None:
return result
return getNode(treeNode.right_child(),key)
In this specific case, since None is falsey, you can use the or operator to do the "short-circuiting" for you:
return getNode(treeNode.left_child(),key) or getNode(treeNode.right_child(),key)
The second recursive call will only be made if the first one returned a falsey value (such as None).
Note that for some recursive algorithms, you may need to recurse multiple times unconditionally, then combine the results together before returning them. For instance, a function to add up the (numeric) key values in a tree might look something like this:
def sum_keys(node):
if node is None: # base case
return 0
left_sum = sumKeys(node.left_child()) # first recursion
right_sum = sumKeys(node.right_child()) # second recursion
return left_sum + right_sum + node.key # add recursive results to our key and return
Without knowing more about your objects:
Three base cases:
current node is None --> return None
current node matches the key --> return it
current node does not match, is the end of the branch --> return None
If not base case recurse. Short circuit the recursion with or: return the left branch if it a match or return the right branch result (which might also be None)
def getNode(treeNode,key):
if treeNode == None:
return None
elif treeNode.key == key:
print("got it=",treeNode.key)
return treeNode
elif not any(treeNode.has_left_child(), treeNode.has_right_child()):
return None
#left_branch = getNode(treeNode.left_child(),key)
#right_branch = getNode(treeNode.right_child(),key)
#return left_branch or right_branch
return getNode(treeNode.left_child(),key) or getNode(treeNode.right_child(),key)
Instead of return, use yield:
class Tree:
def __init__(self, **kwargs):
self.__dict__ = {i:kwargs.get(i) for i in ['left', 'key', 'right']}
t = Tree(key=10, right=Tree(key=20, left=Tree(key=18)), left=Tree(key=5))
def find_val(tree, target):
if tree.key == target:
yield target
print('found')
else:
if getattr(tree, 'left', None) is not None:
yield from find_val(tree.left, target)
if getattr(tree, 'right', None) is not None:
yield from find_val(tree.right, target)
print(list(find_val(t, 18)))
Output:
found
[18]
However, you could also implement the get_node function as a method in your binary tree class by implementing a __contains__ methods:
class Tree:
def __init__(self, **kwargs):
self.__dict__ = {i:kwargs.get(i) for i in ['left', 'key', 'right']}
def __contains__(self, _val):
if self.key == _val:
return True
_l, _r = self.left, self.right
return _val in [[], _l][bool(_l)] or _val in [[], _r][bool(_r)]
t = Tree(key=10, right=Tree(key=20, left=Tree(key=18)), left=Tree(key=5))
print({i:i in t for i in [10, 14, 18]})
Output:
{10: True, 14: False, 18: True}
Hey guys so i have a problem and it is that my return statement is not executing.
This is my sudo code. It searches a tree to see if an item is in the tree.
def search(self, i):
if left child is None and right child is None
if self.data == i:
return True
else:
pass
elif self.data == i:
return True
else:
if left child exists:
return self.left.search(i)
if right child exists:
return self.right.search(i)
The code seems to work except when self.data == i, the code does not run the return True statement even though the
if statement is executed. Does anyone know why this is?
Thanks in advance!
EDIT: ADDED THE SELF PARAMETER. IT WAS SUPPOSED TO BE THERE, WAS A TYPO..
I inserted the numbers 3, 8, 2 and 1 into the tree and then searched for 1. I added a print statement if left child is None and right child is None: if self.data == i: print('self.data == i') return True I added that print statement when searching for 1 and the print statement did print which means that the if statement was executed, however, the return True statement does not execute
I imagine you're trying to do a binary search, in which case you have some problems in your code. The return statement is probably not executed because the condition self.data == i fails. Also, note that if the root has a left child, the right child never gets looked at in your original code.
This is an implementation of a linear search, I'll leave it as an exercise to modify it to a binary search.
def search(self, i):
if self.data == i:
return True
if self.left is not None:
if self.left.search(i):
return True
if self.right is not None:
return self.right.search(i)
return False
Consider the following:
def funcA():
some process = dynamicVar
if dynamicVar == 1:
return dynamicVar
else:
print "no dynamicVar"
def main():
outcome = funcA()
If the 'some process' part results in a 1, the var dynamicVar is passed back as outcome to the main func. If dynamicVar is anything but 1, the routine fails as no arguments are being return.
I could wrap the outcome as a list:
def funcA():
outcomeList = []
some process = dynamicVar
if dynamicVar == 1:
outcomeList.append(dynamicVar)
return outcomeList
else:
print "no dynamicVar"
return outcomeList
def main():
outcome = funcA()
if outcome != []:
do something using dynamicVar
else:
do something else!
or maybe as a dictionary item. Each of the 2 solutions I can think of involve another set of processing in the main / requesting func.
Is this the 'correct' way to handle this eventuality? or is there a better way?
What is the proper way of dealing with this. I was particularly thinking about trying to catch try: / except: errors, so in that example the uses are reversed, so something along the lines of:
def funcA():
some process = dynamicVar
if dynamicVar == 1:
return
else:
outcome = "no dynamicVar"
return outcome
def main():
try:
funcA()
except:
outcome = funcA.dynamicVar
In Python, all function that do not return a value will implicitly return None. So you can just check if outcome is not None in main().
I believe when you write a function, it's return value should be clear and expected. You should return what you say you will return. That being said, you can use None as a meaningful return value to indicate that the operation failed or produced no results:
def doSomething():
"""
doSomething will return a string value
If there is no value available, None will be returned
"""
if check_something():
return "a string"
# this is being explicit. If you did not do this,
# None would still be returned. But it is nice
# to be verbose so it reads properly with intent.
return None
Or you can make sure to always return a default of the same type:
def doSomething():
"""
doSomething will return a string value
If there is no value available, and empty string
will be returned
"""
if check_something():
return "a string"
return ""
This handles the case with a bunch of complex conditional tests that eventually just fall through:
def doSomething():
if foo:
if bar:
if biz:
return "value"
return ""
So I'm fairly new to Python but I have absolutely no idea why this strong oldUser is changing to current user after I make the parse call. Any help would be greatly appreciated.
while a < 20:
f = urllib.urlopen("SITE")
a = a+1
for i, line in enumerate(f):
if i == 187:
print line
myparser.parse(line)
if fCheck == 1:
result = oldUser[0] is oldUser[1]
print oldUser[0]
print oldUser[1]
else:
result = user is oldUser
fCheck = 1
print result
user = myparser.get_descriptions(firstCheck)
firstCheck = 1
print user
if result:
print "SAME"
array[index+1] = array[index+1] +0
else:
oldUser = user
elif i > 200:
break
myparser.reset()
I don't understand why result doesn't work either... I print out both values and when they're the same it's telling me they're not equal... Also, why does myparser.parse(line) turn oldUser into a size 2 array? Thanks!
** Here's the definition for myparse...
class MyParser(sgmllib.SGMLParser):
"A simple parser class."
def parse(self, s):
"Parse the given string 's'."
self.feed(s)
self.close()
def __init__(self, verbose=0):
"Initialise an object, passing 'verbose' to the superclass."
sgmllib.SGMLParser.__init__(self, verbose)
self.divs = []
self.descriptions = []
self.inside_div_element = 0
def start_div(self, attributes):
"Process a hyperlink and its 'attributes'."
for name, value in attributes:
if name == "id":
self.divs.append(value)
self.inside_div_element = 1
def end_div(self):
"Record the end of a hyperlink."
self.inside_div_element = 0
def handle_data(self, data):
"Handle the textual 'data'."
if self.inside_div_element:
self.descriptions.append(data)
def get_div(self):
"Return the list of hyperlinks."
return self.divs
def get_descriptions(self, check):
"Return a list of descriptions."
if check == 1:
self.descriptions.pop(0)
return self.descriptions
Don’t compare strings with is. That checks if they’re the same object, not two copies of the same string. See:
>>> string = raw_input()
hello
>>> string is 'hello'
False
>>> string == 'hello'
True
Also, the definition of myparser would be useful.
I'm not quite sure what your code is doing, but I suspect you want to use == instead of is. Using is compares object identity, which is not the same as string equality. Two different string objects may contain the same sequence of characters.
result = oldUser[0] == oldUser[1]
If you're curious, for more information on the behaviour of the is operator see Python “is” operator behaves unexpectedly with integers.