95

I'm trying to simplify my work and fine-tune the code. What I'm working with is a binary search tree. Right now I have a function in my Tree() class that finds all the elements and puts them into a list.

tree = Tree()
#insert a bunch of items into tree

then I use my makeList() function to take all the nodes from the tree and puts them in a list. To call the makeList() function, I do tree.makeList(tree.root). To me this seems a little repetitive. I'm already calling the tree object with tree.so the tree.root is just a waste of a little typing.

Right now the makeList function is:

    def makeList(self, aNode):
        if aNode is None:
            return []
        return [aNode.data] + self.makeList(aNode.lChild) + self.makeList(aNode.rChild)

I would like to make the aNode input a default parameter such as aNode = self.root (which does not work) that way I could run the function with this, tree.makeList().

First question: why doesn't that work?
Second question: is there a way that it can work (for this kind of recursive function)? As you can see the makeList() function is recursive so I cannot unconditionally initialize as any constant value at the beginning of the function or else I get an infinite loop.

EDIT Here is all the code as requested:

class Node(object):
    def __init__(self, data):
        self.data = data
        self.lChild = None
        self.rChild = None

class Tree(object):
    def __init__(self):
        self.root = None

    def __str__(self):
        current = self.root

    def isEmpty(self):
        if self.root == None:
            return True
        else:
            return False

    def insert (self, item):
        newNode = Node (item)
        current = self.root
        parent = self.root

        if self.root == None:
            self.root = newNode
        else:
            while current != None:
                parent = current
                if item < current.data:
                    current = current.lChild
                else:
                    current = current.rChild

            if item < parent.data:
                parent.lChild = newNode
            else:
                parent.rChild = newNode

    def inOrder(self, aNode):
        if aNode != None:
            self.inOrder(aNode.lChild)
            print aNode.data
            self.inOrder(aNode.rChild)

    def makeList(self, aNode):
        if aNode is None:
            return []
        return [aNode.data] + self.makeList(aNode.lChild) + self.makeList(aNode.rChild)


    def isSimilar(self, n, m):
        nList = self.makeList(n.root)
        mList = self.makeList(m.root) 
        print mList == nList 
4
  • 1
    What do you want with 'self' within a module level method? This makes absolutely no seense. If makeList2() is a method of class then please provide correct code and not snippets without context. Commented Apr 5, 2011 at 16:53
  • makeList2() was suppose to be makeList(), I edited it Commented Apr 5, 2011 at 18:06
  • How does this make no sense? I'm trying to use my makeList() function simpler by using a default parameter for the root of the tree instead of having to call it. Commented Apr 5, 2011 at 18:40
  • 1
    I agree with @crh878 that this makes sense. I tried it myself, also for creating a binary search tree. No joke... Commented Apr 24, 2014 at 1:54

3 Answers 3

68

larsmans answered your first question

For your second question, can you simply look before you leap to avoid recursion?

def makeList(self, aNode=None):
    if aNode is None:
        aNode = self.root
    treeaslist = [aNode.data]
    if aNode.lChild:
        treeaslist.extend(self.makeList(aNode.lChild))
    if aNode.rChild:
        treeaslist.extend(self.makeList(aNode.rChild))
    return treeaslist
Sign up to request clarification or add additional context in comments.

Comments

64

It doesn't work because default arguments are evaluated at function definition time, not at call time:

def f(lst = []):
    lst.append(1)
    return lst

print(f()) # prints [1]
print(f()) # prints [1, 1]

The common strategy is to use a None default parameter. If None is a valid value, use a singleton sentinel:

NOTHING = object()

def f(arg = NOTHING):
    if arg is NOTHING:
        # no argument
    # etc.

9 Comments

You can omit the Sentinel. Just use NOTHING = object(). Guaranteed to yield a unique singleton you can check for via is.
I'd strongly advise against making foo(1, None) and foo(1) do different things.
@Glenn: with a one-arg function that must deal with arbitrary objects, it can make sense sometimes.
Ok, I understand why it doesn't work and also how your first code segment continually appends whatever value you add but I'm not fully following what's going on in the second code segment.
@crh878: the point about using None is the most important. The second part constructs an object NOTHING, uses that as the default argument and checks whether that exact object was passed in. If you hide NOTHING (don't export it from your module), it cannot be passed in by client code. is compares objects by memory address.
|
2

If you want to treat None as a valid argument, you could use a **kwarg parameter.

def function(arg1, arg2, **kwargs):
    kwargs.setdefault('arg3', default)
    arg3 = kwargs['arg3']
    
    # Continue with function

function("amazing", "fantastic") # uses default
function("foo", "bar", arg3=None) # Not default, but None
function("hello", "world", arg3="!!!")

I have also seen ... or some other singleton be used like this.

def function(arg1, arg2=...):
    if arg2 is ...:
        arg2 = default

Comments

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.