__repr__ for a binary tree whose constructor has default arguments I recently have been working on a BinaryTree class, and looked into creating a proper __repr__ which when eval'ed would recreate the exact binary tree as the original.

The following code for __repr__ works as expected, but I'm wondering if there is a better way to handle the removal of values which already has a default parameter in the __init__ method of the class. That is, avoiding to use replace() to remove the None cases at the end of __repr__. 

class BinaryTree(object):
    """Structure to hold a binary tree."""

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


    def __repr__(self):
       """Return a string which when eval'ed will rebuild tree"""

       return '{}({}, {}, {})'.format(
                 self.__class__.__name__,
                 repr(self.value),
                 repr(self.left) if self.left else None,
                 repr(self.right) if self.right else None) \
                      .replace(', None, None)', ')') \
                      .replace(', None)', ')')


    def __eq__(self, other):
        """Check if both trees exists, and have same value and subtrees."""

        # Return early if only one of the tree exists
        #   or if only one of them has a right tree
        #   or if only one of them has a left tree
        if (bool(self) ^ bool(other)
            or (bool(self.right) ^ bool(other.right))
            or (bool(self.left) ^ bool(other.left))):

            return False

        # Otherwise compare the values, and that sub trees are equal
        return (self.value == other.value
                and self.right == other.right
                and self.left == other.left)


    def __ne__(self, other):
        """Negated version of BinaryTree.__eq__"""
        return not self.__eq__(other)


Some test code verifying that it actually works:

trees = []
trees.append(('balanced manual', BinaryTree('D', BinaryTree('B', BinaryTree('A'), BinaryTree('C')),
                            BinaryTree('F', BinaryTree('E')))))

trees.append(('alphalevel manual', BinaryTree('A', BinaryTree('B', BinaryTree('D'), BinaryTree('E')), BinaryTree('C', BinaryTree('F')))))
trees.append(('integer_tree manual', BinaryTree(4, BinaryTree(2, BinaryTree(1), BinaryTree(3)), BinaryTree(6, BinaryTree(5)))))
trees.append(('strange_tree manual',
               BinaryTree('G',
                 BinaryTree('C',
                   BinaryTree('B',
                     BinaryTree('A')),
                   BinaryTree('F',
                     BinaryTree('D',
                       None,
                       BinaryTree('E')))),
                 BinaryTree('H',
                   None,
                   BinaryTree('I')))))


for tree_name, tree in trees:
    print('Treename: {}, equal to __repr__ version: {}'.format(tree_name,
                tree == eval(repr(tree))))


I do know that it doesn't hurt to explicitly specify the default parameters when eval'ing the repr version, but I'm contemplating on using some the repr-versions in tests and so on, and the version without None looks a little nicer than the one with:


BinaryTree('D', BinaryTree('B', BinaryTree('A'), BinaryTree('C')), BinaryTree('F', BinaryTree('E')))
BinaryTree('D', BinaryTree('B', BinaryTree('A', None, None), BinaryTree('C', None, None)), BinaryTree('F', BinaryTree('E', None, None), None))
One thing you can simplify is this subexpression:

repr(self.left) if self.left else None


to just:

repr(self.left)


since repr(None) == str(None) == 'None'. Just saves some typing.

Furthermore, when you are doing:

'({}, {}, {})'.format(repr(a), repr(b), repr(c))


that is equivalent to just repring the tuple:

repr((a, b, c))


Other than that, is it worth the added complexity of the replaces? It's not the end of the world that:

repr(BinaryTree(2)) == 'BinaryTree(2, None, None)'


I'd say just keep it simple:

return '{}{}'.format(
          self.__class__.__name__,
          repr((self.value, self.left, self.right)))