Using self.xxxx as a default parameter - Python

39,108

Solution 1

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

Solution 2

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.

Solution 3

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
Share:
39,108

Related videos on Youtube

chrisheinze
Author by

chrisheinze

Updated on July 16, 2021

Comments

  • chrisheinze
    chrisheinze almost 3 years

    I'm trying to simplify one of my homework problems and make the code a little better. 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 is, why doesn't that work?
    Second question is, is there a way that it can work? As you can see the makeList() function is recursive so I cannot define anything at the beginning of the function or 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 
    
    • Andreas Jung
      Andreas Jung about 13 years
      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.
    • chrisheinze
      chrisheinze about 13 years
      makeList2() was suppose to be makeList(), I edited it
    • chrisheinze
      chrisheinze about 13 years
      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.
    • william_grisaitis
      william_grisaitis about 10 years
      I agree with @crh878 that this makes sense. I tried it myself, also for creating a binary search tree. No joke...
    • Stevoisiak
      Stevoisiak over 6 years
  • Admin
    Admin about 13 years
    You can omit the Sentinel. Just use NOTHING = object(). Guaranteed to yield a unique singleton you can check for via is.
  • Glenn Maynard
    Glenn Maynard about 13 years
    I'd strongly advise against making foo(1, None) and foo(1) do different things.
  • Fred Foo
    Fred Foo about 13 years
    @Glenn: with a one-arg function that must deal with arbitrary objects, it can make sense sometimes.
  • chrisheinze
    chrisheinze about 13 years
    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.
  • Fred Foo
    Fred Foo about 13 years
    @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.
  • chrisheinze
    chrisheinze about 13 years
    @larsmans ok I'm getting it. So if you something like a list, Python will continue to add on to that list even after it is done running that function, thus the function is useless if it is ran more than once? But if you assign the value to None and then change it, the function is reusable?
  • Fred Foo
    Fred Foo about 13 years
    @chr878: you've got it. But actually, the list version may be useful sometimes, if you remember this behavior and document it well; it's very like introducing a global variable. I've seen libraries do this. But the None version is far more common.
  • Charlestone
    Charlestone about 7 years
    Why we should use this instead of None?