0

I am trying to define a recursive method to walk all the nodes of a tree. I defined the Tree as the following:

class Tree(object):

    def __init__(self, value, lson=None, sibling=None):
        self.value = value
        if lson:
            self.lson = Tree(lson)
        else: 
            self.lson = None

        if sibling:
            self.sibling = Tree(sibling)
        else:
            self.sibling = None

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

I have the following function that works:

def walk_tree(t):
    # walk in order
    print t
    if t.lson:
        walk_tree(t.lson)
    if t.sibling:
        walk_tree(t.sibling)
    return t

How do I turn this to an instance method?

def walk_tree(self):
    # walk in order
    print self.value
    if self.lson:
        self.walk_tree(self.lson)
    if self.sibling:
        self.walk_tree(self.sibling)
    return self

This will result in Max recursion depth error...

a. Is this how do you implement a recursive method?
b. Is there a justification here to use yield?
c. Is there a justification here to use @staticmethod which recieves a Tree instance?

2
  • It only works if you still have a global walk_tree(). Commented Apr 27, 2014 at 8:53
  • darn you are right, I was wondering that it works. In earlier versions, I saw File "trees1.py", line 59, in walk_tree self.walk_tree() RuntimeError: maximum recursion depth exceeded ` Commented Apr 27, 2014 at 8:56

1 Answer 1

1

Your recursive method is not recursive. It calls a global walk_tree() that may or may not be recursive itself.

To make a method properly recursive, reference the method on the sub-nodes:

def walk_tree(self):
    # walk in order
    print self.value
    if self.lson:
        self.lson.walk_tree()
    if self.sibling:
        self.sibling.walk_tree()
    return self

This only ever prints values, it doesn't return anything but the top-level node to the initial caller.

yield can help give access to the values efficiently, but you do need to remember to yield recursive calls:

def walk_tree(self):
    # walk in order
    yield self.value
    if self.lson:
        for res in self.lson.walk_tree():
            yield res
    if self.sibling:
        for res in self.sibling.walk_tree():
            yield res

or, using Python 3.3 or up, with yield from generator delegation:

def walk_tree(self):
    # walk in order
    yield self.value
    if self.lson:
        yield from self.lson.walk_tree()
    if self.sibling:
        yield from self.sibling.walk_tree()

A static method is just a namespaced function; your original walk_tree() global could be made into a static method, sure, but there is little point unless you feel the namespace clarifies your API.

Sign up to request clarification or add additional context in comments.

4 Comments

@Oz123: Actually, it should have given you an exception about having an argument too many; I've corrected it to delegate to the child nodes.
Thank you! This was the missing piece. Now I have a problem with your walk_tree with yield. It runs, but finishes with an error: TypeError: 'Tree' object is not iterable. I could probably wrap it with Try ... Except, it just feels weired.
@Oz123: then self.lson.walk_tree() or self.sibling.walk_tree() is not a generator but returns a Tree object. Make sure these are all the same type or at least implement walk_tree() the same way; as a generator.
Ok, now everything works. The function, instance method, and instance method with generator. Thanks for that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.