Tree structure with support for inorder and preorder traversal I am learning Tree Data Structures and came up with this code for implementing basic Tree Node using class and performing various Tree based operations like Traversals and others. The code works perfectly but the structure is bothering me a lot, such as this line of code here:

print(tree.size(tree))


How can I improve the code structure?

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

    def __str__(self):
        return self.data

    def inorder(self, node):
        if node is not None:
            self.inorder(node.left)
            print(node.data)
            self.inorder(node.right)

    def preorder(self, node):
        if node is not None:
            print(node.data)
            self.preorder(node.left)
            self.preorder(node.right)

    def size(self, node):
        if node is None:
            return 0
        return self.size(node.left) + 1 + self.size(node.right)


tree = Node(1)
tree.left = Node(2)
tree.right = Node(3)
tree.left.left = Node(4)
tree.left.right = Node(5)

print(tree.size(tree))
Your instinct to question the appropriateness of tree.size(tree) is right.  You should be able to write tree.size() instead.  The problem is that you've written the methods to take a node parameter, when in fact self is a Node.

Therefore, you should define

def size(self):
    return 1 + (self.left.size()  if self.left  is not None else 0) \
             + (self.right.size() if self.right is not None else 0)


so that you can write tree.size().



The __str__ method isn't right: there's nothing that says that data is a string.  (In fact, in your example, they are integers.)  A more reasonable implementation would be

def __str__(self):
    return str(self.data)




It would be better to avoid hard-coding the print() calls in inorder and preorder, so that they can be used to do more than just printing.  In Python, it would be better to yield each datum, so that inorder() and preorder() act as generators.  (Note that this uses yield from, introduced in Python 3.3.)

def inorder(self):
    if self.left is not None:
        yield from self.left.inorder()
    yield self.data
    if self.right is not None:
        yield from self.right.inorder()


… to be called like

for data in tree.inorder():
    print(data)


You would then have the flexibility to write something like sum(data for data in tree.inorder()) to add all of the nodes.