user3388770
user3388770

Reputation: 119

Tree builder and printing nodes in a hierarchy

Is there a better was to print a tree? I am doing the following. I am building a tree with the following code. What mistake am I really doing? it is giving the following error

      63         ret = "\t"*level+repr(self.label)+"\n"          
      64         for child in self.children:     
 ---> 65             ret += child.__str__(level+1)          
      66         return ret          
      67 

TypeError: expected 0 arguments, got 1 

Code attached below

from collections import Counter
from sets import Set

class treenode:
    def __init__(self, values):
        self.label = values
        self.children = {}

    def __str__(self, level=0):
        ret = "\t"*level+repr(self.label)+"\n"
        for child in self.children:
            ret += child.__str__(level+1)
        return ret

    def __repr__(self):
        return '<tree node representation>'

def build_tree(featurerange, featureid, counts):
    if len(sorted(counts)) > 1:
        featuresLeft = featurerange - Set([featureid])
        if not featuresLeft:
            rootnode.children[v] = treenode(counts.most_common(1)[0][0])
        else:
            rootnode.children[v] = build_tree(featuresLeft)
    else:
        rootnode.children[v] = treenode(counts.most_common(1)[0][0])

    return rootnode

featurerange = set([0, 1])
featureid = 1
counts = Counter({'-': 49, '+': 45})  

tree = build_tree(featurerange, featureid, counts)
str(tree)
print tree

Upvotes: 2

Views: 526

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121584

You are setting children to default to an empty dictionary:

def __init__(self, values, children = {}):

shared between instances. You then proceed to replace the same key over and over again with:

rootnode.children[v] = treenode(counts.most_common(1)[0][0])

where v is a global; you haven't shared it in your question, so I don't know what kind of object that is.

Looping over self.children then loops over the keys of the dictionary:

for child in self.children:

child is then not a treenode instance, so the __str__ method doesn't take extra arguments. It is instead that one v value, but it clearly does not implement a object.__str__ method that takes extra arguments.

Perhaps you wanted to make children a list instead? In any case, there are several issues in your code that you need to address:

  • You are using a mutable default argument here, you are creating one dictionary and all your instances share it. See "Least Astonishment" and the Mutable Default Argument for why you want to avoid that. Use:

    def __init__(self, values, children=None):
        if children is None:
            children = {}
    
  • You appear to be using a v global in build_tree(); did you really need to use a dictionary and one key in that dictionary? Shouldn't children be a sequence or collection instead? If so, use list.append() or set.add() grow the collection of children.

  • You appear to be using the deprecated sets.Set() object; use the built-in set() type instead.

The approach itself, provided you actually loop over a collection of treenode objects, works just fine. You could loop over the values of the dictionary, perhaps:

for child in self.children.values():

Upvotes: 2

Related Questions