Binary Tree Preorder Traversal What is the best way to move _add and _preorder methods in class Node to add_node and preorder methods in class BinaryTree such that they have the below class structure:

class Node:
    __init__
    __repr__


class BinaryTree:
    __init__
    add_node
    preorder


Complete Code::

class Node(object):

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

    def __repr__(self):
        return '{}'.format(self.item)

    def _add(self, value):
        new_node = Node(value)

        if not self.item:
            self.item = new_node
        elif not self.left:
            self.left = new_node
        elif not self.right:
            self.right = new_node
        else:
            self.left = self.left._add(value)
        return self

    def _preorder(self):
        print(self.item)
        if self.left:
            self.left._preorder()
        if self.right:
            self.right._preorder()


class BinaryTree(object):

    def __init__(self):
        self.root = None

    def add_node(self, value):
        if not self.root:
            self.root = Node(value)
        else:
            self.root._add(value)

    def preorder(self):
        if self.root:
            return self.root._preorder()


if __name__ == '__main__':

    binary_tree = BinaryTree()
    print( "Adding nodes 1 to 10 in the tree...")
    for i in range(1, 11):
        binary_tree.add_node(i)

    print()
    print( "Printing preorder...")
    binary_tree.preorder()
class Node(object):

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


The parameters left and right are not used in the constructor!  Remove them, or actually use them.



    def _add(self, value):
        new_node = Node(value)

        if not self.item:
            self.item = new_node
        ...


Given self.item is unconditional set in the constructor, this first test seems unnecessary.

        elif not self.left:
            self.left = new_node
        elif not self.right:
            self.right = new_node


Your binary tree does not seem to have any ordering imposed on the left/right nodes.  If there is no left node, you create one even if the new value is larger than the current node.  Similarly, if there is a left node, but no right node, you create a right node even if the value is smaller than the current node.  

        else:
            self.left = self.left._add(value)
        return self


Finally, if both left and right exist, you unconditionally add the new node to the left sub tree, which will create a very unbalanced tree.  Moreover, the newly created new_node is discarded, to be recreated by the _add() method one level down, so is wasteful.  And the sole purpose of return self seems to be so that there is a return value to assign to self.left, which results in the the original value self.left being assigned to itself, so again useless busy work.


  A binary tree does not have any ordering imposed - nodes are added in the following preference: root -> left -> right. Ordering is imposed i[sic] a binary search tree.  – Saurabh


With your sample code, adding the values 1 to 10 to your BinaryTree, you get the following "tree":

                           1
                          / \
                         2   3
                        / \
                       4   5
                      / \
                     6   7
                    / \
                   8   9
                  /
                10   


This is not really a binary tree; it is a stick with leaves.  It could be represented as a list of tuples: [(1,3), (2,5), (4,7), (6,9), (8,), (10,)].

If you wish to create a general binary tree, which does not impose an ordering, you need to include methods for building the desired tree, such as finding the "5" node, and explicitly adding to the right branch.  A generic add_node() doesn't have enough detail to control how the tree is built.