Q:

Python: Recursion: Find number of leaves of binary tree

I am trying to write a function that calculates the number of leaves of a binary tree by incorporating my BinaryTree class:
This is my BinaryTree class:
class BinaryTree:

def __init__(self, data):
    self.data = data
    self.left = None
    self.right = None

def insert_left(self, new_data):
    if self.left == None:
        self.left = BinaryTree(new_data)
    else:
        t = BinaryTree(new_data)
        t.left = self.left
        self.left = t

def insert_right(self, new_data):
    if self.right == None:
        self.right = BinaryTree(new_data)
    else:
        t = BinaryTree(new_data)
        t.right = self.right
        self.right = t

def get_left(self):
    return self.left

def get_right(self):
    return self.right

def set_data(self, data):
    self.data = data

def get_data(self):
    return self.data

And this the function that I wrote: at the moment its not outputting the right values. I think there is something wrong with my recursion but I cannot figure it out:
def num_leaves(my_tree):
    count = 0
    if my_tree.get_left() and my_tree.get_right() is None:
        count += 1
    if my_tree.get_left():
        num_leaves(my_tree.get_left())
    if my_tree.get_right():
        num_leaves(my_tree.get_right())

    return count

an example of an input and output would be:
a = BinaryTree(1)
a.insert_left(2)
a.insert_right(3)
print(num_leaves(a))

output:
0 

instead of 2.
The idea behind my function is that it recurs until it finds a node where the left and right subtree are None, then it adds one to count. This way it finds each leaf.
What am I doing wrong?

A:

You misunderstand the independence of recursive calls.  num_leaves cannot return anything except 0 or 1 (as you wrote it).  Every instance of num_leaves has its own local copy of count.  Instead of trying to do this as a running sum, have num_leaves return the number of leaves at or beneath this point.
Also, you've misused the boolean expression in num_leaves's first if statement.  You didn't explicitly check to see if the left tree is None.  Although what you wrote happens to work the same way, it looks to me like you didn't realize what you're doing.
def num_leaves(my_tree):
    if my_tree is None:
        return 0
    else:
        return num_leaves(my_tree.get_left()) +
               num_leaves(my_tree.get_right())

A:

At first glance your code for num_leaves should be like this:
def num_leaves(my_tree):
    count = 0
    if my_tree.get_left() is None and my_tree.get_right() is None:
        count += 1
    if my_tree.get_left():
        count += num_leaves(my_tree.get_left()) # added count +=
    if my_tree.get_right():
        count += num_leaves(my_tree.get_right()) # added count +=

    return count

I'll post some more improvements to your Tree code.
The way you have implemented it your BinaryTree is simply a binary tree and not a binary search tree. So I guess if you make the simple change I proposed to your code above, it should work fine.
Testing:
This gives 3, as expected:
a = BinaryTree(1)
a.insert_left(2)
a.insert_right(3)
a.insert_right(4)
a.get_right().insert_left(5)
print(num_leaves(a))

This gives 2, as expected:
a = BinaryTree(1)
a.insert_left(2)
a.insert_right(3)
print(num_leaves(a))

This gives 2, as expected:
a = BinaryTree(1)
a.insert_left(2)
a.insert_right(3)
a.get_right().insert_left(5)
print(num_leaves(a))

A:

I would recommend to keep all btree related functions inside the class. That's OOP.
class BinaryTree:
    ... your code ...

    def is_leaf(self):
        return self.right is None and self.left is None

    def count_leaves(self):
        if self.is_leaf():
            return 1
        count = 0
        if self.right is not None:
            count += self.right.count_leaves()
        if self.left is not None:
            count += self.left.count_leaves()
        return count

