Using self.xxxx as a default parameter - Python

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

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

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.